-
-
-
Tổng tiền thanh toán:
-
ATtiny13 làm mạch đếm số lần sử dụng khóa thiết bị
17/05/2026
ATtiny13 đủ dùng để làm mạch đếm số lần sử dụng (usage limiter) kiểu: dùng được N lần → hết lượt → khóa thiết bị.
Mình sẽ hướng dẫn theo hướng thực tế nhất để bạn có thể làm ngay.
1️⃣ Nguyên lý mạch đếm số lần sử dụng
Ví dụ ứng dụng:
- Thiết bị chỉ cho bật 50 lần
- Mỗi lần bật → giảm 1
- Khi = 0 → khóa relay / khóa tín hiệu Enable
ATtiny13 sẽ làm nhiệm vụ:
- Nhận tín hiệu "thiết bị được bật"
- Giảm biến đếm
- Lưu vào EEPROM (để mất điện không mất số lần)
- Nếu = 0 → ngắt tín hiệu điều khiển
👉 Đây chính là “DRM phần cứng” 😄
2️⃣ Sơ đồ chân ATtiny13 dùng
ATtiny13 có 6 I/O là quá đủ.
Đề xuất dùng:
| Chân | Chức năng |
|---|---|
| PB0 | Input phát hiện thiết bị ON |
| PB1 | Output điều khiển Relay / Enable |
| PB2 | LED báo hết lượt |
| PB3 | Nút reset kỹ thuật (tuỳ chọn) |
| PB4 | Không dùng / debug |
3️⃣ Logic hoạt động
Flow:
Khi cấp nguồn:
đọc số lần còn lại từ EEPROM
Nếu số lần = 0:
khóa relay vĩnh viễn
Nếu còn lượt:
chờ tín hiệu thiết bị bật (PB0 = HIGH)
khi phát hiện bật lần đầu:
giảm counter --
lưu EEPROM
cho phép relay hoạt động
⚠️ Quan trọng: phải chống đếm lặp khi thiết bị đang bật.
4️⃣ Cài Arduino core cho ATtiny13
Trong Arduino IDE cài core:
- ATtinyCore by Spence Konde
Chọn:
- Chip: ATtiny13
- Clock: 9.6 MHz internal
5️⃣ Code hoàn chỉnh
Đây là code chuẩn mình đã tối ưu EEPROM + chống ghi quá nhiều.
Khai báo
#include <EEPROM.h>
#define PIN_TRIGGER 0 // PB0 - phát hiện thiết bị bật
#define PIN_RELAY 1 // PB1 - cho phép chạy
#define PIN_LED 2 // PB2 - báo hết lượt
#define PIN_RESET 3 // PB3 - reset kỹ thuật
#define MAX_USE 50 // số lần cho phép
uint8_t counter;
bool alreadyTriggered = false;
Setup
void setup() {
pinMode(PIN_TRIGGER, INPUT);
pinMode(PIN_RELAY, OUTPUT);
pinMode(PIN_LED, OUTPUT);
pinMode(PIN_RESET, INPUT_PULLUP);
counter = EEPROM.read(0);
// Lần đầu chưa ghi EEPROM → set mặc định
if(counter == 0xFF){
counter = MAX_USE;
EEPROM.write(0, counter);
}
if(counter == 0){
lockDevice();
}
}
Loop chính
void loop() {
// nút reset kỹ thuật (ẩn)
if(digitalRead(PIN_RESET) == LOW){
counter = MAX_USE;
EEPROM.write(0, counter);
}
// nếu đã hết lượt → khóa
if(counter == 0){
lockDevice();
return;
}
bool trigger = digitalRead(PIN_TRIGGER);
// phát hiện cạnh lên (thiết bị vừa bật)
if(trigger && !alreadyTriggered){
alreadyTriggered = true;
useOnce();
}
if(!trigger){
alreadyTriggered = false;
}
}
Hàm trừ lượt sử dụng
void useOnce(){
if(counter > 0){
counter--;
EEPROM.write(0, counter);
}
}
Hàm khóa thiết bị
void lockDevice(){
digitalWrite(PIN_RELAY, LOW); // ngắt relay
digitalWrite(PIN_LED, HIGH); // báo hết lượt
while(1); // khóa vĩnh viễn
}
6️⃣ Cách đấu mạch thực tế
Relay enable kiểu này:
Thiết bị ---- Relay ---- nguồn
↑
PB1 điều khiển
PB0 nhận tín hiệu:
- lấy từ công tắc nguồn
- hoặc từ tín hiệu MCU thiết bị
7️⃣ Nâng cấp chống hack (rất nên làm)
Nếu làm sản phẩm bán:
✔ Dùng wear leveling EEPROM
✔ Mã hóa counter
✔ Disable ISP sau khi nạp
Ví dụ mã hóa đơn giản:
EEPROM = counter XOR 0x5A
Người khác đọc EEPROM sẽ không hiểu.
8️⃣ Ý tưởng nâng cao
Có thể thêm:
- đếm giờ sử dụng thay vì số lần
- mở khóa bằng key bí mật
- lưu lịch sử lỗi
- tự huỷ khi bị nạp lại firmware 😈
1️⃣ Wear leveling EEPROM (cực quan trọng)
Vì sao cần?
EEPROM ATtiny13 chỉ ~100.000 lần ghi / 1 ô.
Nếu mỗi lần bật thiết bị bạn ghi 1 lần → chết EEPROM rất nhanh.
👉 Giải pháp: xoay vòng nhiều ô EEPROM
ATtiny13 có 64 byte EEPROM
Ta dùng 32 ô → tuổi thọ tăng 32 lần
Ý tưởng
Không ghi đè địa chỉ 0 nữa.
Thay vào đó tạo "vòng tròn" lưu counter.
[slot0] [slot1] [slot2] ... [slot31]
Mỗi lần dùng:
- tìm slot mới nhất
- ghi sang slot tiếp theo
Cấu trúc dữ liệu lưu
Mỗi slot gồm 2 byte:
| Byte | Nội dung |
|---|---|
| 0 | counter đã mã hóa |
| 1 | checksum |
👉 Tổng dùng 64 byte = full EEPROM.
Hàm checksum siêu nhẹ
uint8_t checksum(uint8_t v){
return v ^ 0xA5;
}
Mã hóa counter (encryption nhẹ)
Không cần crypto nặng. Chỉ cần làm người thường đọc không hiểu.
uint8_t encode(uint8_t v){
return v ^ 0x5A;
}
uint8_t decode(uint8_t v){
return v ^ 0x5A;
}
Tìm slot mới nhất khi khởi động
#define EEPROM_SLOTS 32
uint8_t currentSlot = 0;
void loadCounter(){
uint8_t lastValidSlot = 255;
for(uint8_t i=0;i<EEPROM_SLOTS;i++){
uint8_t data = EEPROM.read(i*2);
uint8_t crc = EEPROM.read(i*2+1);
if(crc == checksum(data)){
lastValidSlot = i;
}
}
if(lastValidSlot == 255){
counter = MAX_USE;
saveCounter();
return;
}
currentSlot = lastValidSlot;
counter = decode( EEPROM.read(currentSlot*2) );
}
Hàm ghi wear leveling
void saveCounter(){
currentSlot++;
if(currentSlot >= EEPROM_SLOTS) currentSlot = 0;
uint8_t data = encode(counter);
EEPROM.write(currentSlot*2, data);
EEPROM.write(currentSlot*2+1, checksum(data));
}
👉 Bây giờ EEPROM sống hàng chục năm.
2️⃣ Mã hóa counter (anti copy EEPROM)
Nếu không mã hóa:
- hacker đọc EEPROM
- copy sang chip mới
→ reset số lần
Sau khi mã hóa:
- dữ liệu không có nghĩa
- không biết byte nào là slot mới
Bạn có thể nâng level:
Thêm KEY riêng cho từng lô sản phẩm
#define SECRET_KEY 0x3C
uint8_t encode(uint8_t v){
return v ^ SECRET_KEY ^ 0x5A;
}
👉 Mỗi batch sản phẩm 1 KEY khác nhau.
3️⃣ Disable ISP sau khi nạp (quan trọng nhất)
Đây là bước chống đọc firmware.
Sau khi test OK → set fuse lock bits.
Lock bits ATtiny13
Có 2 mức khóa:
| Level | Ý nghĩa |
|---|---|
| LB1 | Không đọc flash |
| LB2 | Không đọc + không ghi |
👉 Dùng Mode 3 (full lock)
Burn fuse bằng Arduino as ISP
Sau khi nạp code xong chạy lệnh:
avrdude -p t13 -c usbasp -U lock:w:0xFC:m
Hoặc trong Arduino IDE:
Tools → Burn Bootloader
(ATtinyCore sẽ set lock bits)
Sau khi lock:
Người khác sẽ:
- ❌ không đọc được code
- ❌ không ghi lại chip
- ❌ không reset counter bằng ISP
Muốn hack → phải thay chip mới 😄
4️⃣ Nâng cấp chống thay chip (pro level)
Nếu muốn hardcore hơn:
Thêm kiểm tra signature chip
if(SIGRD != 0x1E9007) selfDestruct();
Hoặc:
- kiểm tra voltage glitch
- kiểm tra debugWire
Nhưng thường 3 bước trên là đủ bán sản phẩm.
5️⃣ Tóm tắt mức bảo mật sau khi áp dụng
| Bảo vệ | Kết quả |
|---|---|
| Wear leveling | EEPROM bền 20–30 năm |
| Mã hóa | Không copy counter |
| Lock fuse | Không đọc firmware |
| Checksum | Không sửa EEPROM |
👉 Với ATtiny13 là mức bảo mật rất tốt.