ตัวเลือกของบรรณาธิการ:

การโฆษณา

บ้าน - คอมพิวเตอร์
ล็อคไบโอเมตริกซ์ - การตั้งค่าสแกนเนอร์และตั้งโปรแกรมไมโครคอนโทรลเลอร์ ล็อคลายนิ้วมือไบโอเมตริกซ์แบบโฮมเมดสำหรับประตูโรงรถ เครื่องสแกนลายนิ้วมือสำหรับเทมเพลต Arduino ต่างๆ

เนื่องจากฉันไม่มีรถยนต์ ฉันจึงไม่จำเป็นต้องพกกุญแจติดตัวไปทุกที่ ด้วยเหตุนี้ ปรากฏว่าหลายครั้งฉันพบว่าตัวเองไม่มีกุญแจอยู่นอกบ้าน และฉันต้องรอให้ญาติคนหนึ่งกลับมาบ้านแล้วให้ฉันเข้าไป และเมื่อถึงจุดหนึ่งฉันก็ตัดสินใจว่าจะต้องทำอะไรบางอย่างกับเรื่องนี้ และออกแบบล็อคโรงรถแบบโฮมเมด

ในโครงการนี้ ฉันจะแสดงวิธีทำล็อคลายนิ้วมือสำหรับประตูหน้าบ้านของคุณ

ขั้นตอนที่ 1: วัสดุ


นี่คือรายการวัสดุและเครื่องมือที่จำเป็น

อิเล็กทรอนิกส์:

  • เครื่องสแกนลายนิ้วมือ (และขั้วต่อ JST)
  • ชุดจอ LCD (พร้อม ATmega328)
  • เอทีนี่85
  • ทรานซิสเตอร์ NPN
  • ลำโพงทวีตเตอร์
  • สายลำโพง
  • กรณี (ในขั้นตอนที่ 9 จะมีไฟล์สำหรับการพิมพ์ 3 มิติ)
  • ฟิล์มทองแดง
  • เครื่องปรับแรงดันไฟฟ้า 5V
  • แบตเตอรี่ 9V
  • ขั้วต่อสำหรับแบตเตอรี่ 9V
  • สวิตช์ SPDT

เพื่อความสะดวก ฉันจะแนบรายการความปรารถนาสำเร็จรูปบนเว็บไซต์ Sparkfun

เครื่องมือ:

  • หัวแร้งและบัดกรี
  • เทปฉนวน
  • สายไฟและจัมเปอร์
  • คีมตัด/เปลื้องผ้า
  • บอร์ดต้นแบบ
  • ตัวต้านทานต่างๆ
  • สกรู
  • เจาะ
  • ไฟ LED หลายดวงสำหรับการทดสอบ
  • บอร์ด FTDI 5V
  • ปืนกาวร้อน
  • เข้าถึงเครื่องพิมพ์ 3 มิติ
  • อุปกรณ์เสริม: ซ็อกเก็ต IC (8 พินสำหรับ ATtiny และ 28 พินสำหรับ ATmega)
  • ทางเลือก: บอร์ด Arduino อีกตัว / ตัวเก็บประจุ 10uF (รายละเอียดในขั้นตอนที่ 5)

ขั้นตอนที่ 2: แผนภาพอุปกรณ์






ชุด LCD ที่ซื้อจาก Sparkfun มาพร้อมกับ ATmega328 ที่ควบคุมการแสดงผล ATmega328 ค่อนข้างทรงพลังและสามารถใช้ได้ไม่เพียงแต่สำหรับการควบคุมการแสดงผลเท่านั้น แต่ยังใช้กับงานอื่นๆ ได้ด้วย ด้วยเหตุนี้ เราจึงสามารถใช้แทน Arduino เพื่อสื่อสารกับเครื่องสแกนลายนิ้วมือ และส่งคำสั่งไปยัง ATtiny85 ควบคุมการแสดงผลและเสียงบี๊บได้

เพื่อป้องกันไม่ให้ล็อคประตูไบโอเมตริกซ์ทำงานตลอดเวลา ฉันจึงสร้างสวิตช์เข้าไปซึ่งจะทำงานทันทีที่ปิดเคส หากปิดเคส อุปกรณ์จะไม่จ่ายไฟให้กับอุปกรณ์ และเราจะประหยัดทรัพยากรแบตเตอรี่

หมายเหตุสำคัญ: เครื่องสแกนลายนิ้วมือทำงานที่ 3.3V ดังนั้นฉันขอแนะนำให้ใช้ตัวแบ่งแรงดันไฟฟ้าที่จะแปลงสัญญาณจาก ATmega เป็น 3.2V ตัวแบ่งแรงดันไฟฟ้าประกอบด้วยตัวต้านทาน 560 โอห์มระหว่างพินสแกนเนอร์ D10/วินาที และตัวต้านทาน 1K ระหว่างพินสแกนเนอร์ GND/วินาที

พินเอาท์ LCD:

  • D10 - พินสแกนเนอร์ 1 (สายสีดำ)
  • D11 - สแกนเนอร์พิน 2 (ผ่านตัวแบ่งแรงดันไฟฟ้า)
  • D12 - ATtiny85
  • D13 - เสียงแหลม

พินเอาท์ ATtiny85:

  • Pin 5 (0 ในรหัสโปรแกรม) - อินพุตจาก ATmega
  • พิน 3 (4 ในรหัสโปรแกรม) - ทรานซิสเตอร์ / LED สีเหลือง
  • Pin 7 (2 ในโค้ดโปรแกรม) - LED แสดงสถานะ

ขั้นตอนที่ 3: การประกอบส่วนประกอบจากชุด LCD

ชื่อของขั้นตอนนี้บ่งบอกความเป็น: คู่มือเริ่มต้น/การประกอบฉบับย่อที่มีประโยชน์และสะดวก

ขั้นตอนที่ 4: การประกอบวงจรบนบอร์ดต้นแบบ




การจัดวางส่วนประกอบบนบอร์ดขึ้นอยู่กับคุณ เพียงพยายามบัดกรีสายไฟเพื่อให้หันไปในทิศทางเดียวกันและไม่แตกหัก

เมื่อประกอบเสร็จแล้ว ฉันปิดด้านบนและด้านล่างของบอร์ดด้วยกาวร้อน ซึ่งจะช่วยยึดและหุ้มฉนวนองค์ประกอบของวงจร กาวร้อนจะไม่ทำให้ชิปเสียหาย

เช่นเดียวกับเมนบอร์ด ให้บัดกรีทุกอย่างเข้ากับบอร์ด ATtiny และใช้กาวร้อนเพื่อยึดและแยกส่วนประกอบต่างๆ เครื่องปรับแรงดันไฟฟ้าอาจมีความร้อนสูงได้ ดังนั้นจึงควรหลีกเลี่ยงการทากาวร้อนหรือพื้นผิวใดๆ ในบริเวณใกล้เคียง วิธีที่ดีที่สุดคืออย่าปิดบอร์ด ATtiny ด้วยกาวร้อน เนื่องจากคุณอาจต้องการถอดออกและตั้งโปรแกรมใหม่

ขั้นตอนที่ 5: การเขียนโปรแกรม ATmega328

ตามที่กล่าวไว้ในขั้นตอนที่ 2 ATmega328 มีโปรเซสเซอร์ที่แข็งแกร่งเพียงพอและมีพินเพียงพอสำหรับ การควบคุมจอแอลซีดีในขณะที่ควบคุมส่วนประกอบเพิ่มเติมอื่นๆ เพื่อให้บรรลุเป้าหมายนี้ คุณจะต้องตั้งโปรแกรมชิป

ถ้าคุณมี อาร์ดูโน่ อูโน่หรือ Duemilanove คุณสามารถถอดชิปออกจากพวกมันแล้วแทนที่ด้วยชิปที่มาพร้อมกับชุดอุปกรณ์ หรือคุณสามารถหาบอร์ดฝ่าวงล้อมพื้นฐาน FTDI (5V) และสิ่งที่แนบบัดกรีที่ด้านข้าง (ดูรูปในขั้นตอนที่ 3)

คุณจะต้องอัปโหลดโค้ดในโหมด "Duemilanove w/ ATmega328"

รหัสด้านล่าง - โปรแกรมการทำงานเพื่อตรวจสอบการทำงานของอุปกรณ์

#รวม "LiquidCrystal.h" จอแอลซีดี LiquidCrystal (2,3,4,5,6,7,8); การตั้งค่าเป็นโมฆะ () ( pinMode (9, OUTPUT); // backlight pinMode (13, OUTPUT); // beeper lcd.begin (16, 2); // กว้าง 16 ตัวอักษร, digitalWrite สูง 2 อัน (9, สูง) ; / /เปิดไฟแบ็คไลท์ lcd.print(" Hello world! "); // จัดกึ่งกลางข้อความโดยใช้ช่องว่าง (2000); void loop() ( // เสียงบี๊บเปิดและปิด สถานะจะแสดงบนจอแสดงผล .clear( ); lcd.print(" Buzzer is on "); ล่าช้า (1000); lcd.print (" Buzzer is off ");

ขั้นตอนที่ 6: การตั้งค่าเครื่องสแกนลายนิ้วมือ

ฉันใช้ไลบรารีนี้เพื่อสื่อสารกับเครื่องสแกน ลิงค์ดาวน์โหลดโดยตรง

หากต้องการตรวจสอบว่าโค้ดของคุณใช้งานได้หรือไม่ ให้ดาวน์โหลดเครื่องมือทดสอบการกะพริบนี้

เครื่องสแกนลายนิ้วมือมีหน่วยความจำในตัวสำหรับจัดเก็บข้อมูล ดังนั้นหลังจากที่คุณแน่ใจว่าเครื่องสแกนทำงานแล้ว ให้ดาวน์โหลดโปรแกรมนี้เพื่อเพิ่มลายนิ้วมือของคุณลงในฐานข้อมูลภายใต้ id #0 เปิดคอนโซลซีเรียลของคุณแล้วทำตามคำแนะนำ

โปรแกรม LED กระพริบเพื่อทดสอบสแกนเนอร์

/* โค้ดง่ายๆ นี้จะเปิดและปิด LED ใช้เพื่อทำความเข้าใจว่าการสื่อสารใช้งานได้หรือไม่

*/ #include "FPS_GT511C3.h" #include "SoftwareSerial.h" // การตั้งค่าฮาร์ดแวร์ - เครื่องสแกนนิ้วเชื่อมต่อกับ: // digital pin 10 (arduino rx, fps tx) // digital pin 11 (arduino tx - ตัวต้านทาน 560ohm fps tx - ตัวต้านทาน 1,000 โอห์ม - GND) // สิ่งนี้จะลด 5v tx เหลือประมาณ 3.2v และเราจะไม่ทำให้สแกนเนอร์ของเราหมด FPS_GT511C3 fps (10, 11); การตั้งค่าเป็นโมฆะ ()) ( Serial.begin (9600); fps.UseSerialDebug = true; // คุณสามารถดูข้อความบนหน้าจอการแก้ปัญหาแบบอนุกรม fps.Open (); ) void loop ()) ( // การทดสอบ LED กะพริบสำหรับ สแกนเนอร์ fps SetLED (จริง); // เปิด LED ภายในความล่าช้าของสแกนเนอร์ (1,000); fps.SetLED (เท็จ); // ปิดไฟ LED ภายในความล่าช้าของสแกนเนอร์ (1,000);

#include "FPS_GT511C3.h" #include "SoftwareSerial.h" // การตั้งค่าฮาร์ดแวร์ - เครื่องสแกนนิ้วเชื่อมต่อกับ: // digital pin 10 (arduino rx, fps tx) // digital pin 11 (arduino tx - ตัวต้านทาน 560ohm fps tx - ตัวต้านทาน 1,000 โอห์ม - GND) // สิ่งนี้จะลด 5v tx ลงเหลือประมาณ 3.2v และเราจะไม่ทำให้สแกนเนอร์ของเราหมด FPS_GT511C3 fps (10, 11); การตั้งค่าเป็นโมฆะ ()) ( Serial.begin (9600); ล่าช้า (100); fps.Open (); fps.SetLED (true); ลงทะเบียน (); ) เป็นโมฆะลงทะเบียน ()) ( // ทดสอบการลงทะเบียน // ค้นหา open id int registerid = 0; fps.EnrollStart(enrollid); // การลงทะเบียน Serial.print ("กดนิ้วเพื่อลงทะเบียน #"); ในขณะที่ (fps.IsPressFinger () == false) ล่าช้า (100); .CaptureFinger(true); int iret = 0; if (bret != false) ( Serial.println("Remove finger"); fps.Enroll1(); ในขณะที่(fps.IsPressFinger() == จริง) ล่าช้า (100) ; Serial.println("กดนิ้วเดียวกันอีกครั้ง"); ในขณะที่(fps.IsPressFinger() == false) ล่าช้า(100); bret = fps.CaptureFinger(true); "ลบนิ้ว"); ในขณะที่ (fps.IsPressFinger () == จริง) ล่าช้า (100); () == เท็จ) ล่าช้า (100); bret = fps.CaptureFinger (จริง); Serial.println("ลบนิ้ว"); iret = fps.Enroll3(); if (iret = = 0) ( Serial.println("กำลังลงทะเบียนสำเร็จ");

) else ( Serial.print("การลงทะเบียนล้มเหลวด้วยรหัสข้อผิดพลาด:"); Serial.println(iret); ) ) else Serial.println("ไม่สามารถจับภาพนิ้วที่สามได้");


) else Serial.println("ไม่สามารถจับนิ้วที่สองได้");

) else Serial.println("ไม่สามารถจับภาพนิ้วแรกได้"); ) void loop())( ล่าช้า (100,000); ) ไฟล์

ขั้นตอนที่ 7: ตั้งโปรแกรม ATtiny85

ATtiny85 เป็นเหมือน Arduino ราคาถูกที่ประกอบเป็นชิปตัวเดียว ATtiny85 สามารถตั้งโปรแกรมโดย Arduino อื่นๆ ได้ รวมถึง ATmega328 ที่พบในชุด LCD ของเรา ในโครงการนี้ใช้เพื่อรันคำสั่งง่ายๆ: ตรวจสอบสัญญาณจาก ATmega และเปิดประตูหากสัญญาณถูกต้อง

//รับสัญญาณสั้นจากโมดูลหลักเพื่อปิดการตั้งค่าโมฆะรีเลย์())( pinMode(2,OUTPUT); //ไฟ LED แสดงสถานะผ่าน pinMode ตัวต้านทาน 10K(4,OUTPUT); //พินทรานซิสเตอร์ที่เปิดโรงรถ pinMode (0, INPUT ); // อินพุตล่าช้า (500); // ให้เวลาอุปกรณ์เพื่อเริ่ม digitalWrite (2, HIGH); // LED บ่งชี้ ) void loop ()) (ถ้า (digitalRead (0)) ( / / รูปแบบง่าย ๆ สำหรับการสลับการหน่วงเวลาของทรานซิสเตอร์ (125); if(digitalRead(0)==false)( Delay(55); //เดี๋ยวก่อนเนื่องจากตัวจับเวลา ATtiny ไม่เหมาะถ้า (digitalRead(0))( ล่าช้า (55) ); if(digitalRead(0)= =false)( ล่าช้า(55); if(digitalRead(0))( ล่าช้า(55); if(digitalRead(0)==false)( digitalWrite(4, สูง); / / ทรานซิสเตอร์ “กด” การหน่วงเวลาของปุ่ม (1000 ); digitalWrite(4,LOW); digitalWrite(2,LOW);

ขั้นตอนที่ 8: รหัสสุดท้าย

ด้านล่างนี้เป็นโปรแกรม Arduino ที่ฉันเขียนโดยใช้เครื่องสแกนและไลบรารีการแสดงผล เพื่อให้ชัดเจนว่าเกิดอะไรขึ้นในแต่ละส่วนของโปรแกรม ฉันพยายามแสดงความคิดเห็นทุกอย่างด้วยวิธีที่ดีที่สุดเท่าที่จะเป็นไปได้ หลังจากดาวน์โหลดโค้ดนี้ ทุกอย่างควรจะใช้งานได้ และสิ่งที่ต้องทำคือรวมระบบเข้ากับประตู

คำเตือน: หากไลบรารีสแกนเนอร์ไม่ทำงาน ให้ลองใช้ รุ่นเก่าอาร์ดูโน่ IDE.

รหัสสำหรับ ATmega238:

#include "LiquidCrystal.h" // ไลบรารีการแสดงผล #include "FPS_GT511C3.h" // ไลบรารี fps (เครื่องสแกนลายนิ้วมือ) #include "SoftwareSerial.h" // ใช้โดยไลบรารีสแกนเนอร์ // กำหนดค่าจอแสดงผลและพินสแกนเนอร์ LiquidCrystal lcd ( 2, 3, 4, 5, 6, 7, 8); // แสดง pinout FPS_GT511C3 fps (10, 11); //RX, TX บูลีน isFinger = false; //จริงถ้าไลบรารี fps ตรวจพบนิ้วบนสแกนเนอร์ //พินเอาต์พุต const int buzzerPin = 13; const int แบ็คไลท์พิน = 9; const int attinyPin = 12; const String idNames = ("ตนเอง", "พี่ชาย", "ไรอัน", "แม่", "พ่อ", "ป้า", "คุณยาย", "ซีเด", "บุคคล", "บุคคล", "นิ้วหัวแม่มือ"); การตั้งค่าเป็นโมฆะ ()) ( // ตั้งค่าเอาต์พุต pinMode (buzzerPin, OUTPUT); pinMode (backlightPin, OUTPUT); pinMode (attinyPin, OUTPUT); // สำหรับการดีบัก // Serial.begin (9600); fps.UseSerialDebug = false; / /กลายเป็นจริงสำหรับการดีบัก fps ผ่าน พอร์ตอนุกรม//เตรียมใช้งานไลบรารี lcd.begin(16,2);<30; i++){ tone(buzzerPin, 50+10*i, 30); delay(30); } tone(buzzerPin, 350); //вывод стартового сообщения lcd.print("Put your finger "); //команда вывода на экран lcd.setCursor(0, 1); //устанавливаем курсор на нулевую колонку первой строки lcd.print(" on the scanner "); delay(150); noTone(buzzerPin); //останавливаем стартовый звук } void loop(){ //сканируем и распознаём отпечаток, когда приложен палец waitForFinger(); lcd.clear(); //очищаем экран и устанавливаем курсов в положение 0,0 fps.CaptureFinger(false); //захватываем отпечаток для идентификации int id = fps.Identify1_N(); //идентифицируем отпечаток и сохраняем id if(id <= 10){ lcd.print(" Access granted "); //сообщение об успехе lcd.setCursor(0,1); //выводим на экран имя когда дверь открывается String message = " Hey " + idNames + "!"; lcd.print(message); tone(buzzerPin, 262, 1000); delay(1500); //отправляем сигнал для открытия двери digitalWrite(attinyPin, HIGH); //первый импульс синхронизирует задержку (10ms) delay(5); digitalWrite(attinyPin, LOW); delay(3); digitalWrite(attinyPin, HIGH); //следующие два - открывают дверь delay(15); digitalWrite(attinyPin, LOW); delay(5); digitalWrite(attinyPin, HIGH); delay(10); digitalWrite(attinyPin, LOW); delay(1000); lcd.clear(); lcd.print("Don"t forget to "); lcd.setCursor(0,1); lcd.print(" shut me off! "); delay(2000); waitForFinger(); //нажмите чтобы продолжить запись while(true){ //сохраняет новый отпечаток //выводит сообщение на экран lcd.clear(); lcd.print(centerText("So you want to")); lcd.setCursor(0,1); lcd.print(centerText("scan a new one?")); delay(2000); //Скопировано и слегка модифицировано из примера регистрации данных: int enrollid = 11; //выбираете какой id переписать\создать //отпустите палец, когда хотите записать id/имя, напечатанное на экране waitForFinger(); //ждёт, когда будет нажат fps while(enrollid==11){ for (int i = 1; i1){ lcd.print(i); enrollid = i-1; break; } } } //предупреждение, если в данном слоте уже есть данные if(fps.CheckEnrolled(enrollid)){ lcd.clear(); lcd.print(" Warning! ID #"); lcd.print(enrollid); lcd.setCursor(0,1); lcd.print(" has data. OK? "); delay(2500); waitForFinger(); //ждёт, когда будет нажат fps fps.DeleteID(enrollid); //удаляет данные delay(100); } //Enroll fps.EnrollStart(enrollid); lcd.clear(); lcd.print("Place finger to "); lcd.setCursor(0,1); lcd.print("enroll #"); lcd.print(enrollid); //выводит id, который был добавлен waitForFinger(); //ждёт, когда будет нажат fps //захватывает отпечаток и сохраняет его в память трижды для точности данных bool bret = fps.CaptureFinger(true); //картинка высокого качества для записи int iret = 0; //в случае ошибки if (bret != false){ //первая регистрация lcd.clear(); lcd.print(" Remove finger "); fps.Enroll1(); while(fps.IsPressFinger() == true) delay(100); //ждёт пока уберут палец lcd.clear(); lcd.print(" Press again "); waitForFinger(); //ждёт, когда будет нажат fps bret = fps.CaptureFinger(true); if (bret != false){ //вторая регистрация lcd.clear(); lcd.print(" Remove finger "); fps.Enroll2(); while(fps.IsPressFinger() == true) delay(100); lcd.clear(); lcd.print("Press yet again "); waitForFinger(); bret = fps.CaptureFinger(true); if (bret != false){ //третья регистрация iret = fps.Enroll3(); if (iret == 0){ //проверяет, были ли какие-нибудь ошибки lcd.clear(); lcd.print(" Success! "); delay(2000); beep(); //выключает Ардуино } else{ //запускает этот код в случае любой ошибки lcd.clear(); lcd.print("Fail. Try again "); delay(1000); } } lcd.clear(); lcd.print(" Failed 3rd "); //ошибка на третьей записи delay(1000); } lcd.clear(); lcd.print(" Failed 2nd "); //ошибка на второй записи delay(1000); } lcd.clear(); lcd.print(" Failed 1st "); //ошибка на первой записи delay(1000); } } else{ lcd.print("Fingerprint is"); //если отпечаток не распознан lcd.setCursor(0,1); lcd.print(" unverified "); delay(2000); lcd.clear(); lcd.print("Please try again"); lcd.setCursor(0,1); lcd.print("Use your pointer"); //pointer - указательный палец (можете использовать любой и заменить это слово) delay(500); } delay(250); } void beep(){ //издаёт звуки, чтобы кто-нибудь закрыл кейс lcd.clear(); lcd.print("Please close the"); lcd.setCursor(0,1); lcd.print(" case! "); for(int i=0;i=80 && !fps.IsPressFinger()){ beep(); } } timer = 0; //обнуляет таймер как только функция завершится } String centerText(String s) { //центрует текст на дисплее, чтобы он лучше смотрелся while(16-s.length()>digitalWrite (แบ็คไลท์พิน, สูง); //ไฟหลังจอ LCD fps.เปิด();

ในการสร้างระบบรักษาความปลอดภัยไบโอเมตริกแบบง่ายๆ เพื่อปกป้องรถของคุณจากการเข้าถึงโดยไม่ได้รับอนุญาต เราจะต้องมีเซ็นเซอร์ลายนิ้วมือและไมโครคอนโทรลเลอร์ Arduino โปรเจ็กต์นี้ใช้สื่อการฝึกอบรมของ Adafruit เพื่ออำนวยความสะดวกในการทำซ้ำ จึงมีการใช้โค้ดโปรแกรมที่สมบูรณ์จากเนื้อหานี้ โดยมีการเปลี่ยนแปลงเล็กน้อย

ขั้นแรก เราปรับเปลี่ยนระบบสตาร์ทของรถ การเชื่อมต่อหลักคือตัวนำ IG จากสวิตช์จุดระเบิดซึ่งจ่ายพลังงานให้กับตัวควบคุมแรงดันไฟฟ้า จากนั้นไปยังไมโครคอนโทรลเลอร์ Arduino เพื่อเปิดและปิด และสแกนนิ้วบนเซ็นเซอร์เป็นเวลา 10 วินาที หากลายนิ้วมือตรงกัน ระบบจะเปิดใช้งานกล่องรีเลย์ซึ่งควบคุมรีเลย์สตาร์ทเตอร์ ตอนนี้คุณสามารถสตาร์ทเครื่องยนต์ได้แล้ว หลังจากผ่านไป 10 วินาที เซ็นเซอร์ลายนิ้วมือจะปิดลง คุณสามารถเปิดใหม่ได้โดยทำซ้ำรอบการจุดระเบิด หากภายใน 10 วินาทีเซ็นเซอร์ตรวจไม่พบลายนิ้วมือหรือลายนิ้วมือไม่ตรงกับข้อมูลอ้างอิง ระบบสตาร์ทจะดับลงและเครื่องยนต์จะไม่สตาร์ท

เนื่องจากรถแต่ละคันมีระบบการกำหนดค่าในการสตาร์ทที่แตกต่างกัน คุณจะต้องปรึกษาช่างไฟฟ้าเกี่ยวกับระบบไฟฟ้าของรถหรือตรวจสอบแผนภาพการเดินสายไฟก่อนที่จะปรับเปลี่ยนระบบสตาร์ท

โปรดทราบว่าเซ็นเซอร์ลายนิ้วมือไม่ได้สตาร์ทเครื่องยนต์ เพียงเปิดใช้งานและปิดใช้งานรีเลย์สตาร์ท ซึ่งจะห้ามหรืออนุญาตให้สตาร์ทเครื่องยนต์

ในโปรเจ็กต์นี้ มีการติดตั้งอุปกรณ์กันขโมยในรถยนต์ Mitsubishi Lancer 2000 coupe 2 ประตู

ขั้นตอนที่ 1: ส่วนประกอบที่ใช้

ขั้นตอนที่ 4: กำลังโหลดโปรแกรมหลัก

เชื่อมต่อเซ็นเซอร์ลายนิ้วมือตามที่แสดงในแผนภาพและโหลดโปรแกรมหลัก เชื่อมต่อ LED และตัวต้านทานเข้ากับพิน 12 เพื่อตรวจสอบการทำงานที่ถูกต้อง

โปรแกรมนี้ทำงานบนหลักการของสื่อการเรียนรู้ด้วยลายนิ้วมือของ Adafruit อย่างไรก็ตาม ฉันแก้ไขโค้ดเล็กน้อยและเพิ่มตัวจับเวลาเพื่อปิดเซ็นเซอร์หลังจากผ่านไป 10 วินาทีเพื่อหลีกเลี่ยงการเสียสมาธิจากไฟ LED ที่กะพริบของเซ็นเซอร์

ขั้นตอนที่ 5: การประกอบส่วนที่ 1

ถอดสกรูใต้แผงหน้าปัดออก คลายคันปลดล็อคฝากระโปรง ถอดส่วนล่างของแดชบอร์ดออก วางเซ็นเซอร์ในพื้นที่ว่าง

ขั้นตอนที่ 6: การประกอบส่วนที่ 2

วัดระยะทางที่ต้องการและตัดพื้นที่เล็กๆ ออกเพื่อติดตั้งเซ็นเซอร์อย่างแน่นหนา

ขั้นตอนที่ 7: การประกอบส่วนที่ 3

วิธีที่ดีที่สุดคือติดตั้งบอร์ด Arduino Uno ด้านหลังเซ็นเซอร์ลายนิ้วมือ ฉันปรับเบาะให้คมขึ้นเล็กน้อยเพื่อให้บอร์ด Arduino Uno อยู่ในตำแหน่งที่ถูกต้อง

คุณต้องการอะไร

  1. โมดูลลายนิ้วมือ FPM10A
  2. โมดูลอาร์เอฟไอดี RC522
  3. Arduino mega (ตามทฤษฎีแล้วบอร์ดอื่นสามารถใช้ได้ แต่ฉันเลือกอันนี้เนื่องจากจำนวนพิน)
  4. 1 ใบอนุญาตสำหรับ 1C 8.2 (ไคลเอนต์แบบหนาในกรณีของฉันตัดเองเพื่อแบบบาง)
  5. การสื่อสารผ่านพอร์ต Com โดยใช้ MsCommLib.MsComm (คุณต้องมีใบอนุญาต คุณยังสามารถ google ได้ที่นี่)
  6. สภาพแวดล้อมการพัฒนาสำหรับ Arduino (ใช้แล้ว 1.8.5)
  7. แท็บเล็ตที่มีอินเทอร์เฟซ USB
  8. สายรัด: ตัวต้านทาน 1 กิโลโอห์ม ปุ่มลัดวงจร สายไฟ เทปไฟฟ้า "สีน้ำเงิน" เครื่องวิเคราะห์คืบทางความร้อนทางทวารหนัก หากต้องการ (คุณสามารถบิดสายไฟได้หากคุณมีความรู้สึกใกล้ชิดและอธิบายไม่ได้ที่เกี่ยวข้องกับอุปกรณ์นี้) สาย USB สำหรับ Arduino แขนตรง และการโน้มน้าวใจที่คดเคี้ยวของชื่อเล่นเฉลี่ย 1s รวมถึง เพื่อสร้างร่างกายเพื่อการอัศจรรย์ทั้งหมดนี้

หมายเหตุ: ในภาพสีของสายไฟแตกต่างกัน - ระหว่างขั้นตอนการติดตั้งสายไฟหลายเส้นขาดเนื่องจาก... พวกเขาเป็น Huawei โดยสมบูรณ์และฉันต้องใช้สีอื่นที่มีอยู่

ระบบข้อความถูกทำซ้ำในช่วงเวลาวิกฤติโดยตั้งใจ
ฉันเตือนคุณทันทีว่าวิศวกรทั่วไปอาจมีน้ำตาไหลออกมาจากดวงตาของพวกเขาจากขัดสน แต่นี่เป็นโครงการ Arduino งานแรกของฉันและเป็นหนึ่งในความซับซ้อนดังกล่าวและดูเหมือนว่าจะทำงานและทำงานได้อย่างเสถียร ตอนแรกมีความคิดที่จะทำทุกอย่างผ่านเครือข่าย (wifi + แบบมีสาย) แต่หลังจากประมาณค่าใช้จ่ายในการแก้ไขข้อบกพร่องและสร้างบริการ http ของตัวเองและใช้งานทุกอย่างใน 1C ฉันตัดสินใจใช้ com ไม่ว่าในกรณีใด ตรรกะทั้งหมด สามารถถ่ายโอนไปยังการประมวลผลภายนอกได้โดยไม่ต้องเปลี่ยนการกำหนดค่า

คุณยังสามารถแทรกระบบสำหรับการถ่ายภาพพนักงานที่เข้ามาผ่านกล้องเว็บของแท็บเล็ต เพิ่มรีเลย์และประตูควบคุมอิเล็กทรอนิกส์ บูรณาการอย่างสมบูรณ์กับ ZUP ผ่านการประมวลผลภายนอกที่ส่งผ่านพารามิเตอร์การเปิดตัวและการทำลายล้างงานรื่นเริงสำหรับเกตเวย์ที่เป็นอันตรายอย่างยิ่งซึ่งมีความสำคัญเป็นความลับ) .

ยินดีรับฟังคำวิจารณ์ที่เป็นประโยชน์

อารัมภบท

เมื่อเห็นราคาสำหรับระบบการเข้าถึงและระบบติดตามเวลาที่มีอยู่ สาระสำคัญสีเขียวก็เริ่มทำให้ฉันหายใจไม่ออก หลังจากเดินไปรอบๆ Arduino และโมดูลต่างๆ เป็นเวลานาน ฉันก็เจอโมดูลลายนิ้วมือ FPM10A โมดูลนี้สามารถจัดเก็บลายนิ้วมือจำนวนมากได้ตั้งแต่ 50 ถึงอนันต์ในหน่วยความจำแฟลช ทั้งนี้ขึ้นอยู่กับเวอร์ชัน และใช้ในโมดูลส่วนใหญ่ของผู้ผลิตอุปกรณ์ควบคุมไบโอเมตริกซ์ อย่างไรก็ตาม ในโครงการของฉัน เนื่องจากไลบรารีนี้ จึงจำกัดไว้ที่ 254 รายการ ฉันขอเตือนคุณทันทีว่าฉันกำลังโพสต์ไลบรารี่ที่ค้นพบอย่างละเอียดถี่ถ้วนสำหรับ Arduino เพราะ... ฉันต่อสู้กับการค้นหามาเป็นเวลานานและเสียเวลา 3 วันในการค้นหาและแก้ไขข้อบกพร่องของไลบรารีสำหรับโมดูลนี้

คำอธิบายของโมดูล

ไลบรารีที่ใช้ในโครงการอนุญาตให้ใช้ลายนิ้วมือได้สูงสุด 256 (ไบต์) จำนวนนี้มากเกินไปสำหรับฉัน ในกรณีที่ร้ายแรง คุณสามารถใช้ 1 โมดูลสำหรับพนักงานทุกๆ 256 คน
จำนวนแท็ก RFID ถูกจำกัดด้วยเอกลักษณ์ของ UID เท่านั้น ฐานข้อมูลสามารถจัดเก็บใน 1C และเชื่อมโยงกับพนักงาน สามารถใช้แท็กที่เข้ากันได้ทั้งหมด ตามทฤษฎีแล้ว สามารถใช้คีย์ใด ๆ สำหรับอินเตอร์คอม การ์ดเมโทร และการ์ดทรอยก้าได้
การเชื่อมต่อกับ 1c จะต้องผ่านพอร์ต com ผ่านไลบรารี MsCommLib.MsComm แต่สามารถเขียนใหม่ไปยังไลบรารีอื่นได้ ควรติดตั้งไดรเวอร์สำหรับพอร์ต com สำหรับ Arduino พร้อมกับสภาพแวดล้อมการพัฒนา Arduino แต่ก็สามารถใช้งาน Google ได้
ทุกอย่างที่บัดกรีถูกซ่อนอยู่ในกล่องที่เชื่อมต่อผ่านเครือข่าย (ฉันใช้ WiFi แต่คุณสามารถใช้การ์ดเครือข่าย USB ภายนอกได้)

อัลกอริธึมการทำงาน

ฮาร์ดแวร์:

  1. เราประสาน / บิดโมดูล Arduino
  2. เราเชื่อมต่อกับโปรแกรมเมอร์พีซีและอัปโหลดเฟิร์มแวร์ไปยัง Arda ทำการทดสอบ ตรวจสอบให้แน่ใจว่าคำสั่งใช้งานได้
  3. พวกเขาเชื่อมต่อผ่าน USB กับแท็บเล็ต Windows 10 เราแทนที่ด้วยการโหลดอัตโนมัติ:

A) ผ่านไฟล์เนื้อหา:

    เริ่มต้น - ดำเนินการ: เชลล์: การเริ่มต้น

    สร้างไฟล์ที่นั่นโดยใช้ Notepad ด้วยชื่อ hz.bat และเนื้อหา (ฉันแน่ใจว่าคุณสามารถจัดการพารามิเตอร์ฐานข้อมูลไฟล์ได้ด้วยตัวเอง - ฉันมี sql): “C:\Program Files\1cv8\ ... \bin\1cv8 .exe” องค์กร / SServerName:พอร์ต\DBName" /NUser /PPassword

B) เราทำขั้นสูงกว่านี้โดยการแทนที่เชลล์โดยใช้สคริปต์ VB (อย่าลืมสร้างผู้ใช้รายอื่นนอกเหนือจากค่าเริ่มต้นโดยไม่ต้องเปิดเชลล์):

    สร้างไฟล์โดยใช้ Notepad ด้วยชื่อ C:\hz\hz.vbs และเนื้อหา

ตั้ง oShell=createobject("wscript.shell")
sCmd="""C:\Program Files\1cv8\ ... \bin\1cv8.exe"" องค์กร /SServerName:พอร์ต\DBName" /NUser /PPassword"
oShell.run sCmd จริง
sCmd="ปิดเครื่อง /r /t 0"
oShell.run sCmd

    เริ่มต้น - ดำเนินการ: regedit ตามสาขา: User\Software\Microsoft\Windows ปัจจุบัน NT\CurrentVersion\Winlogon

    เพิ่มพารามิเตอร์สตริง "Shell" (REG_SZ)

    แก้ไข: "wscript C:\hz\hz.vbs" (ไม่มีเครื่องหมายคำพูดในพารามิเตอร์)

    รีบูตและทดสอบ 1c ควรเริ่มต้นโดยไม่มี explorera

  1. ต่อไปเราตรวจสอบให้แน่ใจว่ามันใช้งานได้และบรรจุลงในกล่อง

โดยทางโปรแกรม:

  1. ในสภาวะปกติ Arduino จะสำรวจเครื่องสแกนลายนิ้วมือ เครื่องสแกน RFID ปุ่มการจัดการ และส่งคำสั่งรอผ่านพอร์ต com
  2. ทันทีที่นิ้วปรากฏในมุมมองของผู้อ่าน เราจะส่งคำสั่งไปยังพอร์ต com และ 1c จะมองเห็น ID นิ้วหรือ UID ของแท็กผ่านการอ่านตัวแปร
  3. จำเป็นต้องใช้ปุ่มเพื่อจัดการลายนิ้วมือ เมื่อคุณกด 1c จะถามรหัสผ่านเข้าสู่ระบบ จากนั้นจะสามารถกำหนดรหัสสแกนเนอร์หรือ UID ของการ์ดให้กับพนักงานผ่านระบบส่งข้อความได้

ในการสื่อสารกับ 1c จะใช้บรรทัดต่อไปนี้ (ฉันทำการประมวลผลสำหรับ conf และไทม์ชีทของฉัน ซึ่งอยู่ในโครงการเป็นตัวอย่าง แต่รวมอยู่ในซอร์สโค้ด):

การเชื่อมต่อกับพอร์ตคอม

ขั้นตอน StartSystem() ComPort = COMObject ใหม่ ("MsCommLib.MsComm");

ลอง ComPort.CommPort = 3;

ComPort.Settings = "9600,N,8,1";

ComPort.แฮนด์เชค = 0;

ComPort.InBufferCount = 0;<>"" จากนั้น hSeconds = hSeconds + 1;

สิ้นสุดถ้า;

ถ้า hSeconds > 60 ดังนั้น PreEmployee = 0;

ชั่วโมงวินาที = 0;

สิ้นสุดถ้า; มิฉะนั้นคำเตือน ("พอร์ตไม่เปิด"); ThisForm.Close(); สิ้นสุดถ้า; สิ้นสุดขั้นตอน กระบวนการ สตริงที่เข้ารหัส (ข้อมูลกีฬา) อาร์เรย์ = ข้อมูลกีฬา ปุ่ม const intPin = 2; // หมายเลขอินพุตที่เชื่อมต่อกับปุ่มเพื่อเข้าสู่โหมดการเขียนโปรแกรม int buttonState = 0; // ตัวแปรสำหรับจัดเก็บสถานะปุ่ม int modeState = 0; // ตัวแปรสำหรับจัดเก็บสถานะอุปกรณ์ 0 - กำลังรอเครื่องสแกนลายนิ้วมือ 1 - การเขียนโปรแกรม uint8_t id; // หมายเลขประจำตัวที่จะบันทึกเทมเพลตลายนิ้วมือ String frcUID = ""; // หมายเลขประจำตัวผู้อ่าน rfid int rfidYes = 0; // อินพุต RFID SoftwareSerial mySerial สำเร็จ (10, 11); // ประกาศวัตถุ mySerial ให้ทำงานกับไลบรารี SoftwareSerial OBJECT_NAME(RX, TX); // คุณสามารถระบุพินใด ๆ ที่รองรับ PCINTx ขัดจังหวะ Adafruit_Fingerprint finger = Adafruit_Fingerprint(&mySerial); // ประกาศวัตถุนิ้วให้ทำงานกับไลบรารี Adafruit_Fingerprint OBJECT_NAME = Adafruit_Fingerprint(PARAMETER); // PARAMETER - ลิงก์ไปยังออบเจ็กต์สำหรับการทำงานกับ UART ที่โมดูลเชื่อมต่ออยู่ เช่น &Serial1 MFRC522 mfrc522(53, 5); // สร้างการตั้งค่าโมฆะของอินสแตนซ์ MFRC522() ( pinMode(buttonPin, INPUT); // เริ่มต้นพินที่เชื่อมต่อกับปุ่มเป็นอินพุต Serial.begin(9600); // เริ่มต้นฮาร์ดแวร์ UART ที่ความเร็ว 9600 ในขณะที่ (!Serial); / / กำลังรอความล่าช้าในการเริ่มต้นฮาร์ดแวร์ UART (500); // Init SPI bus mfrc522.PCD_Init(); // Init MFRC522 mfrc522.PCD_DumpVersionToSerial(); // แสดงรายละเอียดของ PCD - MFRC522 Card Reader ล่าช้า (500); / กำลังรอโมดูลลายนิ้วมือเพื่อเริ่มต้น Serial.println(". . . Scan sensor . . . "); // แสดงข้อความ "กำลังค้นหาเซ็นเซอร์" finger.begin(57600); // กำลังเริ่มต้นซอฟต์แวร์ UART ที่ความเร็ว 57600 ( ความเร็วของโมดูลเริ่มต้น) Serial.println(finger.verifyPassword()); if (finger.verifyPassword()) ( Serial.println(". . . พบเซ็นเซอร์! . . . "); // หากตรวจพบโมดูลลายนิ้วมือ พิมพ์ข้อความ "sensor found" ) else ( Serial.println(". . . ไม่พบเซ็นเซอร์ . . . "); // หากไม่พบโมดูลลายนิ้วมือ ให้แสดงข้อความ "ไม่พบเซ็นเซอร์" และเข้าสู่วงวนไม่สิ้นสุด : ในขณะที่(1 ); - - พบ ID=" + สตริง(finger.fingerID) + ", ความมั่นใจ=" + สตริง(finger.confidence) + "! - - "; Serial.println(frcUID); ) ) ) if (mfrc522.PICC_IsNewCardPresent()) ( ล่าช้า (100); if (mfrc522.PICC_ReadCardSerial()) ( //mfrc522.PICC_DumpToSerial(&(mfrc522.uid)); frcUID = ""; สำหรับ (ไบต์ i = 0; i< mfrc522.uid.size; i++) { frcUID = frcUID + (mfrc522.uid.uidByte[i]); } frcUID = ". . . Found RFID UID=" + frcUID + "@ . . ."; Serial.println(frcUID); } } delay(100); // Задержка перед следующим сканированием 0,5 сек (нет смысла запускать на полной скорости) Serial.println(". . . Please put your finger on the scanner or rfid . . ."); break; case 1: Serial.println(". . . Programming mode . . ."); // Входим в режим программирования delay(400); Serial.println(". . . Programming mode . . ."); // Входим в режим программирования delay(400); Serial.println(". . . Programming mode . . ."); // Входим в режим программирования delay(400); Serial.println(". . . Programming mode . . ."); // Входим в режим программирования id = readnumber(); // Ожидание получения цифры, введённой с COM-порта if (id >IndexMin = SportsData.GetLowerBound(0);< 254) { // Если 254 то rfid иначе палец 0-253 modeState = 2; // Пытаемся отсканировать палец } else { modeState = 3; // Пытаемся отсканировать rfid uid } } break; case 2: while (!getFingerprintEnroll()); // Пытаемся получить ответ об присваивании ID modeState = 1; break; case 3: rfidYes = 0; Serial.println(". . . Put RFID in Scanner! . . ."); delay(400); Serial.println(". . . Put RFID in Scanner! . . ."); delay(400); Serial.println(". . . Put RFID in Scanner! . . ."); delay(5000); if (mfrc522.PICC_IsNewCardPresent()) { // Пытаемся отсканировать rfid uid delay(100); if (mfrc522.PICC_ReadCardSerial()) { //mfrc522.PICC_DumpToSerial(&(mfrc522.uid)); frcUID = ""; for (byte i = 0; i < mfrc522.uid.size; i++) { frcUID = frcUID + (mfrc522.uid.uidByte[i]); } frcUID = ". . . New RFID UID=" + frcUID + "@ . . ."; rfidYes = 1; Serial.println(frcUID); delay(400); Serial.println(frcUID); delay(400); Serial.println(frcUID); delay(400); Serial.println(frcUID); } } if (rfidYes == 0) { Serial.println(". . . RFID error! . . ."); delay(400); } modeState = 1; break; } } // функция возвращает номер, введённый с COM-порта uint8_t readnumber(void) { int num = -1; // Переменная с номером, который требуется вернуть while (num < 0) { // Вход в цикл, пока переменная num не станет >IndexMax = SportsData.GetUpperBound(0);< 0) { num = 0; // Увеличиваем значение num на один порядок } else { num *= 10; } num += c - "0"; // Прибавляем к значению num цифру из переменной c } delay(5); // Задержка на 5мс, чтоб в буфер COM-порта успели догрузиться следующие символы (если таковые имеются) } } return num; // Возвращение введённого числа } uint8_t getFingerprintEnroll() { int p; // Переменная для получения результатов выполнения функций //Загрузка первого изображения отпечатка пальца p = -1; Serial.println(". . . Please put your new finger on the scanner . . ."); // Вывод сообщения "Пожалуйста положите Ваш палец на сканер" delay(400); Serial.println(". . . Please put your new finger on the scanner . . ."); // Вывод сообщения "Пожалуйста положите Ваш палец на сканер" delay(400); Serial.println(". . . Please put your new finger on the scanner . . ."); // Вывод сообщения "Пожалуйста положите Ваш палец на сканер" delay(400); Serial.println(". . . Please put your new finger on the scanner . . ."); // Вывод сообщения "Пожалуйста положите Ваш палец на сканер" while (p != FINGERPRINT_OK) { // Вход в цикл, пока переменная p не станет равна константе FINGERPRINT_OK (корректная загрузка изображения) p = finger.getImage(); // Захватываем изображение и возвращаем результат выполнения данной операции в переменную p switch (p) { // Проверка ответа... case FINGERPRINT_OK: Serial.println(" Ok!"); break; // Изображение отпечатка пальца корректно загрузилось case FINGERPRINT_NOFINGER: Serial.println(". . . Please put your new finger on the scanner . . ."); break;// Сканер не обнаружил отпечаток пальца case FINGERPRINT_PACKETRECIEVEERR: Serial.println(". . . Communication error . . ."); break; // Ошибка соединения case FINGERPRINT_IMAGEFAIL: Serial.println(". . . Imaging error Please try again . . ."); break; // Ошибка изображения default: Serial.println(". . . Unknown error Please try again . . ."); break; // Неизвестная ошибка } } //Конвертирование изображения первого отпечатка пальца p = finger.image2Tz(1); Serial.print (". . . Image converting . . ."); // Конвертируем первое изображение и возвращаем результат выполнения данной операции в переменную p switch (p) { // Проверка ответа... case FINGERPRINT_OK: Serial.println("Ok!"); break; // Изображение сконвертировано case FINGERPRINT_IMAGEMESS: Serial.println(". . . Image too messy . . ."); return p; // Изображение слишком нечеткое case FINGERPRINT_PACKETRECIEVEERR: Serial.println(". . . Communication error . . ."); return p; // Ошибка соединения case FINGERPRINT_FEATUREFAIL: Serial.println(". . . No fingerprint on image . . ."); return p; // Ошибка конвертирования case FINGERPRINT_INVALIDIMAGE: Serial.println(". . . No fingerprint on image . . ."); return p; // Ошибка изображения default: Serial.println(". . . Unknown error . . ."); return p; // Неизвестная ошибка } //Просим убрать палец от сканера p = 0; while (p != FINGERPRINT_NOFINGER) { // Вход в цикл, пока переменная p не станет равна константе FINGERPRINT_NOFINGER (сканер не обнаружил отпечаток пальца) Serial.println(". . . Please remove your finger from the scanner . . ."); // Вывод сообщения "Пожалуйста уберите Ваш палец со сканера" delay(400); p = finger.getImage(); // Захватываем изображение и возвращаем результат выполнения данной операции в переменную p } Serial.println(" Ok!"); //Загрузка второго изображения отпечатка пальца p = -1; Serial.println(". . . Place same finger again . . ."); // Вывод сообщения "Пожалуйста положите тот же палец еще раз" delay(400); while (p != FINGERPRINT_OK) { // Вход в цикл, пока переменная p не станет равна константе FINGERPRINT_OK (корректная загрузка изображения) p = finger.getImage(); // Захватываем изображение и возвращаем результат выполнения данной операции в переменную p switch (p) { // Проверка ответа... case FINGERPRINT_OK: Serial.println(" Ok!"); break; // Изображение отпечатка пальца корректно загрузилось case FINGERPRINT_NOFINGER: Serial.println(". . . Place same finger again . . ."); break; // Сканер не обнаружил отпечаток пальца case FINGERPRINT_PACKETRECIEVEERR: Serial.println(". . . Communication error . . ."); break; // Ошибка соединения case FINGERPRINT_IMAGEFAIL: Serial.println(". . . Imaging error . . ."); break; // Ошибка изображения default: Serial.println(". . . Unknown error . . ."); break; // Неизвестная ошибка } } //Конвертирование изображения второго отпечатка пальца p = finger.image2Tz(2); Serial.print (". . . Image 2 converting . . ."); // Конвертируем второе изображение и возвращаем результат выполнения данной операции в переменную p switch (p) { // Проверка ответа... case FINGERPRINT_OK: Serial.println("Ok!"); break; // Изображение сконвертировано case FINGERPRINT_IMAGEMESS: Serial.println(". . . Image too messy . . ."); return p; // Изображение слишком нечеткое case FINGERPRINT_PACKETRECIEVEERR: Serial.println(". . . Communication error . . ."); return p; // Ошибка соединения case FINGERPRINT_FEATUREFAIL: Serial.println(". . . No fingerprint on image . . ."); return p; // Ошибка конвертирования case FINGERPRINT_INVALIDIMAGE: Serial.println(". . . No fingerprint on image . . ."); return p; // Ошибка изображения default: Serial.println(". . . Unknown error . . ."); return p; // Неизвестная ошибка } //Создание модели (шаблона) отпечатка пальца, по двум изображениям p = finger.createModel(); Serial.print (". . . Creating model . . ."); // Создание модели (шаблона) отпечатка пальца, по двум изображениям if (p == FINGERPRINT_OK) { Serial.println(". . . Model create! Ok! . . ."); } else // Модель (шаблон) отпечатка пальца создана if (p == FINGERPRINT_PACKETRECIEVEERR) { Serial.println(". . . Communication error . . ."); return p; } else // Ошибка соединения if (p == FINGERPRINT_ENROLLMISMATCH) { Serial.println(". . . Fingerprints did not match . . ."); return p; } else // Отпечатки пальцев не совпадают { Serial.println(". . . Unknown error . . ."); // Неизвестная ошибка return p; } //Сохранение, ранее созданной, модели (шаблона) отпечатка пальца, под определённым ранее, идентификационным номером p = finger.storeModel(id); //Serial.println(". . . Saving model . . ."); Serial.println(". . . Saving model . . ."); //Serial.println(". . . Saving model in ID="); Serial.print(id); Serial.print(": "); // Сохранение модели (шаблона) отпечатка пальца, по двум изображениям if (p == FINGERPRINT_OK) { frcUID = ". . . Model save in ID=" + String(id) + "! . . ."; Serial.println(frcUID); delay(1500); Serial.println(frcUID); delay(400); Serial.println(frcUID); delay(400); Serial.println(frcUID); } else // Модель (шаблон) отпечатка пальца сохранена if (p == FINGERPRINT_PACKETRECIEVEERR) { Serial.println(". . . Communication error . . ."); return p; } else // Ошибка соединения if (p == FINGERPRINT_BADLOCATION) { Serial.println(". . . Could not store in that location . . ."); return p; } else // Не удалось сохранить в этом месте if (p == FINGERPRINT_FLASHERR) { Serial.println(". . . Error writing to flash . . ."); return p; } else // Ошибка записи в flash память { Serial.println(". . . Unknown error . . ."); // Неизвестная ошибка return p; } }

StringInfo = "";

สำหรับดัชนี = IndexMin โดย IndexMax - 1 รอบ SymbolReceived = AbbrLP(Array.Get(Index));

หาก CharacterReceived = "13" ดังนั้นหากไม่ถูกระงับ ดังนั้น RowInfo = RowProcessing(RowInfo); //นี่คือการประมวลผลข้อความ EndIf;

อื่น LineInfo = LineInfo + สัญลักษณ์ (หมายเลข (สัญลักษณ์ที่ได้รับ));

สิ้นสุดถ้า;

สิ้นสุดรอบ; สิ้นสุดขั้นตอน

เครื่องอ่านลายนิ้วมือ PQI Mini USB เป็นตัวเลือกที่ยอดเยี่ยมสำหรับผู้ที่ต้องการให้อุปกรณ์เก่ามีชีวิตที่สอง สแกนเนอร์ถูกสร้างขึ้นโดยเฉพาะเพื่อทำงานกับฟีเจอร์ Hello ใหม่ที่มีในอุปกรณ์ที่ใช้ Windows 10 อย่างไรก็ตาม อุปกรณ์ยังรองรับระบบปฏิบัติการ Windows 7 และ 8 เวอร์ชันต่างๆ อีกด้วย

ข้อดีหลักประการหนึ่งของเซ็นเซอร์คือมีความสามารถในการสแกนแบบ 360 องศา คุณจึงไม่ต้องกังวลกับวิธีที่ดีที่สุดในการเชื่อมต่ออุปกรณ์ของคุณกับพีซี ใช้พอร์ต USB ที่ใกล้ที่สุดแล้วเริ่มต้นใช้งาน เมื่อเครื่องสแกนต้องการลายนิ้วมือ เครื่องจะหมุนไปยังตำแหน่งที่ต้องการโดยอัตโนมัติ และเปรียบเทียบข้อมูลที่ได้รับกับสำเนาที่บันทึกไว้

เครื่องอ่านลายนิ้วมือ PQI Mini USB สามารถจัดเก็บโปรไฟล์ได้มากถึง 10 โปรไฟล์ ทำให้อุปกรณ์นี้เหมาะสำหรับการแชร์หรือเมื่อคุณต้องการสแกนนิ้วเพิ่มเติม (หากนิ้ว "หลัก" สกปรกหรือได้รับบาดเจ็บ)

เครื่องอ่านลายนิ้วมือ PQI Mini USB มีจำหน่ายในราคาที่สมเหตุสมผล ทำให้เป็นตัวเลือกที่ยอดเยี่ยมสำหรับผู้ที่กำลังมองหารุ่นเริ่มต้น นอกจากนี้สแกนเนอร์ยังพกพาสะดวกพอที่จะพกพาไปได้ทุกที่โดยไม่ต้องยุ่งยากมากนัก

เครื่องอ่านลายนิ้วมือ Verifi P2000

หากคุณใช้คอมพิวเตอร์เดสก์ท็อปที่ไม่สามารถเข้าถึงพอร์ต USB ได้ง่ายนัก ให้ใส่ใจกับเครื่องอ่านลายนิ้วมือ Verifi P2000 เชื่อมต่อกับพีซีได้อย่างง่ายดายและที่สำคัญสามารถวางไว้ใกล้กับคอมพิวเตอร์เพื่อการใช้งานที่สะดวกสบายยิ่งขึ้น

สแกนเนอร์ทำจากโลหะกันกระแทกและมีอายุการใช้งานหลายปี แม้จะมีการออกแบบที่ทนทาน แต่ก็มีอัตราการจดจำลายนิ้วมือที่ดี ดังนั้นคุณไม่จำเป็นต้องเปลี่ยนตำแหน่งนิ้วของคุณตลอดเวลาเพื่อให้ได้การจับคู่ที่สมบูรณ์แบบ ในกรณีส่วนใหญ่ การปัดเซ็นเซอร์เพียงครั้งเดียวก็เพียงพอแล้ว

เมื่อสร้าง P2000 Verifit วางแผนที่จะทำให้อุปกรณ์มีความทนทาน เพื่อไม่ให้มีผลกระทบต่อกระบวนการสแกนและความแม่นยำของผลการจดจำ เครื่องอ่านลายนิ้วมือ Verifi P2000 เป็นอุปกรณ์พกพาที่คุณสามารถพกพาติดตัวไปได้อย่างง่ายดาย นอกจากนี้ยังสามารถใช้งานร่วมกับคอมพิวเตอร์จำนวนมากกว่ารุ่นอื่นที่คล้ายคลึงกัน

เคนซิงตัน เวริมาร์ค

สำหรับเครื่องสแกนลายนิ้วมือที่มีขนาดเล็กอย่างไม่น่าเชื่อ Kensington VeriMark มีเกือบทุกอย่างที่คุณต้องการเพื่อประสบการณ์ที่สะดวกสบาย รุ่นนี้รองรับการสแกน 360 องศาและมีขนาดเล็ก แต่สิ่งสำคัญที่ทำให้ Kensington VeriMark มีคุณค่ามากคือฟังก์ชันเพิ่มเติม

อุปกรณ์จัดเก็บข้อมูลที่ได้รับทั้งหมดในรูปแบบที่เข้ารหัส เมื่อเซ็นเซอร์สแกนลายนิ้วมือ เซ็นเซอร์จะเข้ารหัสทันที เป็นไปไม่ได้ที่จะขัดจังหวะกระบวนการนี้ ดังนั้นการแฮ็กซอฟต์แวร์หรือฮาร์ดแวร์และการแยกข้อมูลไบโอเมตริกซ์จึงเป็นไปไม่ได้

นอกจากนี้ อุปกรณ์ยังใช้เทมเพลตพิเศษในการถอดรหัสการสแกนที่ได้รับ ซึ่งมีเพียงผู้ผลิตเท่านั้นที่มี ทำให้มีความปลอดภัยมากขึ้นจากการโจมตีของแฮ็กเกอร์และความพยายามอื่น ๆ ในการเข้าถึงโดยไม่ได้รับอนุญาต

สแกนเนอร์รองรับการทำงานกับพอร์ตที่ค่อนข้างเก่า โดยไม่คำนึงถึงเวอร์ชันที่วางจำหน่าย หากคุณใช้รุ่นที่มี จากนั้นใช้อะแดปเตอร์ USB-C เป็น USB-A คุณสามารถเชื่อมต่ออุปกรณ์กับแล็ปท็อปหรือคอมพิวเตอร์ที่ค่อนข้างเก่าที่ไม่รองรับพอร์ต USB ที่ทันสมัยกว่าได้

เครื่องวิเคราะห์เครื่องอ่านลายนิ้วมือ Benss

เครื่องวิเคราะห์เครื่องอ่านลายนิ้วมือ Benss เป็นอีกหนึ่งสแกนเนอร์ที่สามารถทำให้ชีวิตของคุณง่ายขึ้นและช่วยคุณจากปัญหามากมาย ตามกฎแล้ว โมเดลที่เรียบง่ายกว่าจะถ่ายภาพควบคุมหนึ่งภาพก่อน หลังจากนั้นงานพิมพ์ที่ตามมาทั้งหมดจะถูกเปรียบเทียบกับผลลัพธ์เริ่มต้น ซึ่งหมายความว่าหากมีสิ่งใดเกิดขึ้นกับรูปภาพต้นฉบับ (ซึ่งมีการเปรียบเทียบการสแกนอื่นๆ ทั้งหมด) โอกาสที่ผลลัพธ์สุดท้ายจะตรงกันจะลดลงอย่างมาก

เครื่องวิเคราะห์เครื่องอ่านลายนิ้วมือ Benss ทำงานร่วมกับอัลกอริธึมการเรียนรู้ด้วยตนเองที่สร้างและอัปเดตโปรไฟล์ของคุณโดยอัตโนมัติทุกครั้งที่สัมผัส ยิ่งคุณใช้อุปกรณ์นานเท่าไร ผลลัพธ์ก็จะยิ่งแม่นยำมากขึ้นเท่านั้น ทำให้สแกนเนอร์ยากขึ้นที่จะหลอกด้วยลายนิ้วมือปลอม เนื่องจากเซ็นเซอร์จะสแกนนิ้วของคุณอย่างต่อเนื่องและอัพเดตฐานข้อมูล จึงตรวจจับความพยายามในการเข้าถึงโดยไม่ได้รับอนุญาตได้ทันที

นี่เป็นหนึ่งในอุปกรณ์ที่มีประสิทธิภาพสูงสุดในการตอบโต้การโจมตีของแฮ็กเกอร์ อัตราการยอมรับที่ผิดพลาดนั้นน้อยกว่า 0.002% ซึ่งหมายความว่าคุณต้องพยายามแฮ็กอุปกรณ์จริงๆ ในขณะเดียวกันก็ไม่ทำให้งานซับซ้อนมากนัก ค่าสัมประสิทธิ์ FRR (อัตราการปฏิเสธที่ผิดพลาด - การปฏิเสธการเข้าถึงบุคคลที่ลงทะเบียนในระบบ) มีเพียง 3%

IDEM BioScan ขนาดกะทัดรัด

หากคุณกำลังมองหาสแกนเนอร์ที่สามารถปรับแต่งได้ คุณจะต้องชอบ IDEM BioScan Compact หากต้องการขยายขีดความสามารถพื้นฐานและรับฟังก์ชันเพิ่มเติม เพียงดาวน์โหลดซอฟต์แวร์พิเศษจากเว็บไซต์อย่างเป็นทางการของผู้ผลิต

หลังจากนี้ คุณจะสามารถเข้ารหัสไฟล์และโฟลเดอร์แต่ละไฟล์ในคอมพิวเตอร์ของคุณ รวมถึงเก็บข้อมูลการเข้าสู่ระบบและรหัสผ่านสำหรับการเข้าถึงเว็บไซต์ในโปรแกรมพิเศษ วิธีนี้ทำให้คุณสามารถเข้าสู่พอร์ทัลอินเทอร์เน็ตใดๆ ก็ได้โดยเพียงแค่แตะเซ็นเซอร์ด้วยนิ้วของคุณ

แม้ว่าคุณจะไม่ได้คำนึงถึงฟังก์ชันการทำงานเพิ่มเติม แต่ BioScan Compact ก็ถือเป็นรุ่นที่คุ้มค่า อุปกรณ์นี้สามารถจัดเก็บลายนิ้วมือได้ถึง 10 ลายนิ้วมือ มีขนาดที่เล็ก และการรักษาความปลอดภัยในตัวเพื่อจดจำข้อมูลไบโอเมตริกซ์ปลอม

Blucoil SecuGen หนูแฮมสเตอร์โปร 20

Blucoil SecuGen Hamster Pro 20 เป็นเครื่องสแกนลายนิ้วมือในอุดมคติสำหรับความต้องการระดับมืออาชีพ เนื่องจากรุ่นนี้มีการตั้งค่าความปลอดภัยขั้นสูง ราคาจึงสูงกว่าอุปกรณ์อื่นๆ ในรายการของเราเกือบสองเท่า

นอกจากนี้ยังเป็นหนึ่งในสแกนเนอร์ไม่กี่เครื่องที่รองรับ Linux อย่างเป็นทางการ ดังนั้นไม่ว่าคุณจะใช้ระบบปฏิบัติการใดก็ตาม เซนเซอร์ก็เหมาะสำหรับทุกงาน

SecuGen Hamster Pro 20 เป็นอุปกรณ์กันกระแทกที่ป้องกันรอยขีดข่วน น้ำ และฝุ่น เครื่องสแกนสามารถติดตามร่องรอยที่เหลือจากการสแกนครั้งก่อน และปฏิเสธผลลัพธ์ที่ไม่ชัดเจน

นอกจากนี้ Blucoil SecuGen Hamster Pro 20 ยังเป็นอุปกรณ์ประหยัดพลังงานดังนั้นจึงปิดโดยอัตโนมัติหากไม่มีใครใช้เป็นเวลานาน

ความปลอดภัยพิเศษ

ในช่วงไม่กี่ปีที่ผ่านมา มีการเปิดตัวอุปกรณ์เคลื่อนที่และเดสก์ท็อปจำนวนมากที่มีเครื่องสแกนลายนิ้วมือในตัว และมีจำนวนเพิ่มขึ้นทุกปีเท่านั้น หากคอมพิวเตอร์ของคุณไม่มีเซ็นเซอร์ในตัวสำหรับจดจำข้อมูลไบโอเมตริกซ์ก็ไม่ต้องกังวล มีสแกนเนอร์ USB มากมายสำหรับพีซีและแล็ปท็อป เข้ากันได้กับรุ่นยอดนิยมเกือบทั้งหมด

ในการสร้างการเชื่อมต่อกับเซ็นเซอร์ลายนิ้วมือ มีการใช้คำแนะนำจาก Josh Hawley (ดาวน์โหลดคำแนะนำโดยตรง)

หากต้องการแก้ไขข้อบกพร่องการทำงานของเครื่องสแกนลายนิ้วมือด้วยการแสดงตัวอักษร จำเป็นต้องมีการซิงโครไนซ์

เซ็นเซอร์ลายนิ้วมือมีหน่วยความจำของตัวเองสำหรับจัดเก็บภาพที่สแกน ดังนั้นหลังจากที่เซ็นเซอร์เริ่มทำงาน ให้ดาวน์โหลดโดยเพิ่มลงในฐานข้อมูลลายนิ้วมือที่อยู่ 0 เปิดคอนโซลการจัดการบนคอมพิวเตอร์ของคุณแล้วปฏิบัติตามป๊อปอัปพร้อมท์

รหัส - ตัวอย่างการกะพริบ:

/* ตัวอย่างไลบรารีสำหรับควบคุมเครื่องสแกนลายนิ้วมือ GT-511C3 (FPS) */ #include "FPS_GT511C3.h" #include "SoftwareSerial.h" //การตั้งค่าฮาร์ดแวร์ - FPS เชื่อมต่อกับ: //digital pin 10(arduino rx, fps tx) // พินดิจิตอล 11 (arduino tx - ตัวต้านทาน 560ohm fps tx - ตัวต้านทาน 1,000ohm - กราวด์) // สิ่งนี้ทำให้สาย 5v tx ลงไปที่ประมาณ 3.2v ดังนั้นเราจึงไม่ทอด fps FPS_GT511C3 fps ของเรา (10, 11); การตั้งค่าเป็นโมฆะ())( Serial.begin(9600); fps.UseSerialDebug = true; // เพื่อให้คุณสามารถเห็นข้อความในหน้าจอดีบักแบบอนุกรม fps.Open(); ) void loop())( // FPS Blink LED ทดสอบ fps .SetLED(จริง); // เปิด LED ภายในการหน่วงเวลา fps (1,000); fps.SetLED (เท็จ); // ปิด LED ภายในการหน่วงเวลา fps (1,000);

รหัส – ตัวอย่างการลงทะเบียน:

/* FPS_Enroll.ino - ตัวอย่างไลบรารีสำหรับควบคุมเครื่องสแกนลายนิ้วมือ GT-511C3 (FPS) */ #include "FPS_GT511C3.h" #include "SoftwareSerial.h" // การตั้งค่าฮาร์ดแวร์ - FPS เชื่อมต่อกับ: // พินดิจิทัล 10 (arduino rx, fps tx) // พินดิจิตอล 11 (arduino tx - ตัวต้านทาน 560ohm fps tx - ตัวต้านทาน 1,000ohm - กราวด์) // สิ่งนี้ทำให้เส้น 5v tx ลดลงเหลือประมาณ 3.2v ดังนั้นเราจึงไม่ทอด fps FPS_GT511C3 fps ของเรา (10, 11); การตั้งค่าเป็นโมฆะ ()) ( Serial.begin (9600); ล่าช้า (100); fps.Open (); fps.SetLED (true); ลงทะเบียน (); ) เป็นโมฆะลงทะเบียน ()) ( // ลงทะเบียนทดสอบ // ค้นหาเปิด ลงทะเบียน id int registerid = 0; fps.EnrollStart (ลงทะเบียน); // ลงทะเบียน Serial.print ("กดนิ้วเพื่อลงทะเบียน #"); ในขณะที่ (fps.IsPressFinger () == false) ล่าช้า (100) ; .CaptureFinger(true); int iret = 0; if (bret != false) ( Serial.println("ลบนิ้ว"); fps.Enroll1(); ในขณะที่(fps.IsPressFinger() == true ) ล่าช้า (100) ; Serial.println("กดนิ้วเดิมอีกครั้ง"); ในขณะที่(fps.IsPressFinger() == false) ล่าช้า(100); ( Serial.println("ลบนิ้ว"); fps.Enroll2(); ในขณะที่(fps. IsPressFinger() == true) ล่าช้า (100); Serial.println ("กดนิ้วเดียวกันอีกครั้ง"); ในขณะที่ (fps. IsPressFinger () == false) ล่าช้า (100); if (bret != false) ( Serial.println("Remove finger"); iret = fps.Enroll3(); if (iret == 0) ( Serial.println("การลงทะเบียนสำเร็จ");

) else ( Serial.print("การลงทะเบียนล้มเหลวด้วยรหัสข้อผิดพลาด:"); Serial.println(iret); ) ) else Serial.println("ไม่สามารถจับภาพนิ้วที่สามได้");

) else Serial.println("ไม่สามารถจับนิ้วที่สองได้");

) else Serial.println("ไม่สามารถจับภาพนิ้วแรกได้"); ) โมฆะวง ()) (ล่าช้า (100,000); )

ซิงค์ไฟล์:

ไฟล์ทะเบียนร่าง:

ขั้นตอนที่ 7: การเขียนโปรแกรมโปรเซสเซอร์ ATtiny85

ไมโครชิป ATtiny85 มีราคาถูก และเข้ากันได้กับบอร์ด Arduino โดยสมบูรณ์ ซึ่งอาจเป็นชิ้นส่วนไฟฟ้าที่ดีที่สุดเท่าที่เคยมีมา!

จำเป็นต้องใช้โปรแกรมเมอร์ Arduino เพื่อรีเฟรชชิป ATmega328 ซึ่งควบคุมการทำงานของจอแสดงผล LCD ในอุปกรณ์ที่ประกอบ โปรเซสเซอร์ ATtiny จะดำเนินการคำสั่งง่ายๆ: ตรวจสอบสัญญาณจาก ATmega และเปิดประตูโรงรถเมื่อสัญญาณได้รับการยืนยันในการตั้งโปรแกรมโปรเซสเซอร์ จะต้องเชื่อมต่อโดยใช้เขียงหั่นขนมกับโปรแกรมเมอร์พร้อมกับตัวเก็บประจุ 10 uF ดังที่แสดงในภาพด้านล่าง แล้วดาวน์โหลด.

หลังจากนั้น จะต้องสลับเอาต์พุต 13 บนบอร์ด Arduino ที่เชื่อมต่อกับ LED ไปที่สถานะ HIGH เพื่อตรวจสอบการทำงานโดยใช้ไฟแสดงสถานะ

รหัสสุดท้ายสำหรับ แอตตินี่ :

//fpsAttiny โดย Nodcah //รับสัญญาณสั้นๆ จากโมดูลหลักเพื่อปิดการตั้งค่าโมฆะรีเลย์())( pinMode(2,OUTPUT); //ตัวบ่งชี้ที่นำผ่านตัวต้านทาน 10K pinMode(4,OUTPUT); //trasistor pin ที่เปิด pinMode ของโรงรถ (0, INPUT); // อินพุตล่าช้า (500); // ให้เวลาสิ่งต่าง ๆ เพื่อเริ่มต้น digitalWrite (2, HIGH); // ตัวบ่งชี้ LED เป็นโมฆะ ()) (ถ้า (digitalRead (0) ) ( // รูปแบบง่าย ๆ เพื่อกระตุ้นการหน่วงเวลาของทรานซิสเตอร์ (125); if (digitalRead (0) == false) ( ล่าช้า (55); // การกำหนดเวลาปิดอยู่เนื่องจากตัวจับเวลาของ ATtiny ไม่สมบูรณ์ถ้า (digitalRead ( 0))( ล่าช้า (55); if(digitalRead(0)==false)( ล่าช้า(55); if(digitalRead(0))( ล่าช้า(55); if(digitalRead(0)==false)( digitalWrite (4, สูง); // ทรานซิสเตอร์ "กด" ความล่าช้าของปุ่ม (1,000); digitalWrite (2, ต่ำ);

ล็อคไบโอเมตริกซ์ - โค้ดสุดท้าย ตัดฝาครอบ เตรียมโรงจอดรถนาฬิกา GPS บน Arduino ล็อคไบโอเมตริกซ์ - แผนผังจอแสดงผล LCD และชุดประกอบ



 


อ่าน:


ใหม่

วิธีฟื้นฟูรอบประจำเดือนหลังคลอดบุตร:

วิธีรีเซ็ตรหัสผ่านผู้ดูแลระบบบน Mac OS X โดยไม่ต้องใช้แผ่นดิสก์การติดตั้ง

วิธีรีเซ็ตรหัสผ่านผู้ดูแลระบบบน Mac OS X โดยไม่ต้องใช้แผ่นดิสก์การติดตั้ง

แม้จะมีชื่อที่ไม่ชัดเจน แต่บทความนี้จะไม่เกี่ยวกับการแฮ็กบัญชีใน Mac OS X (คุณสามารถอ่านเกี่ยวกับเรื่องนี้ได้หากต้องการ...

การตั้งค่า Shadow Defender

การตั้งค่า Shadow Defender

และอื่นๆ อีกมากมาย โดยเฉพาะอย่างยิ่ง เราได้กล่าวถึงสิ่งต่างๆ เช่น (ซึ่งสามารถทำหน้าที่ป้องกันการติดเชื้อได้ หรืออย่างน้อยก็เป็นวิธีหนึ่งในการกลับมา...

ทำไมโปรเซสเซอร์ในคอมพิวเตอร์ของฉันถึงร้อนจัด?

ทำไมโปรเซสเซอร์ในคอมพิวเตอร์ของฉันถึงร้อนจัด?

ฉันไม่ได้วางแผนที่จะเขียนบทความนี้ มีคำถามมากมายเกี่ยวกับแล็ปท็อปที่ร้อนเกินไป การทำความสะอาด และการเปลี่ยนแผ่นระบายความร้อน บน...

โหมด "เทอร์โบ" ในเบราว์เซอร์สมัยใหม่คืออะไร: Chrome, Yandex, Opera

โหมด

เว็บเบราว์เซอร์ชื่อดังมากมาย เช่น Yandex.Browser มีโหมด “Turbo” พิเศษ ซึ่งสามารถเพิ่มความเร็วได้อย่างมาก...

ฟีดรูปภาพ อาร์เอสเอส