mình đang làm bài truyền thông giữa 4 AVR loại ATmega 16 để tạo thành 1 đường bus.(3 con slave +1con master),truyền data từ slave về master truyền lên PC.mong các cao thủ chỉ giáo cách tạo đường Bus.có ví dụ minh họa thì càng tuyệt.
Thông báo
Collapse
No announcement yet.
hothothot Tạo đường truyền BUS giữa 4 atmega 16
Collapse
X
-
Chỉ truyền có 4 con với nhau không thì dùng một số giao thức cơ bản đều được hết. Nếu khoảng cách xa có thể dùng chuẩn RS485,CAN, gần dùng chuẩn RS232, SPI, I2C... Nếu là bài tập trong nhà trường thì dùng chuẩn SPI hoặc RS232 là hợp lý hơn hết. Với SPI thì dễ quá rồi. Tôi giới thiệu khái quát thêm với RS232.
Cách làm với RS232 cơ bản như sau:
+ Cách lắp phần cứng
- Tất cả chân RX, TX của ATmega đều được nối với MAX232. Gọi chung là TX232 và RX232.
- TX232 của con Master nối với các chân RX232 của Slave. Slave gồm 3 con còn lại và cổng COM giao tiếp máy tính.
- RX232 của con Master nối với các chân TX232 của con Slave bao gồm cả chân TXD (chân số 3) của COM giao tiếp máy tính.
Tóm lại lấy một con ATmega16 làm Master, 3 con ATmega còn lại và máy tính làm slave
Đến đây đã hoàn thành công đoạn nối bus truyền.
Tiếp theo là công đoạn tạo dựng khung truyền thông đồng bộ nhau.
+ Khung truyền thông giao tiếp:
Cần có khung truyền thông giữa các con với nhau. Và cần phân biệt các con slave với nhau.
Cách làm như sau:
Đặt địa chỉ ID cho con Slave đầu tiên là ID = 1, con tiếp theo là ID = 2,...3, máy tính là 4.
Khung truyền thông sẽ gồm 2 byte Header dùng để nhận biết bắt đầu của khung.
Với Khung từ Master xuống Slave cần 2 byte Header, kế đến là byte ID rồi đến byte lệnh CMD, và đến các byte dữ liệu, kết thúc là byte kiểm tra tổng Checksum.
Còn từ Slave gửi lên Master thì : 2 byte Header, kế đến là ID của con Slave, rồi đến dữ liệu, và kết thúc là Checksum.n
ĐT: 0986 492 489
Tham khảo:
Comment
-
Tôi xin viết tiếp.
Nếu ta muốn ra lệnh cho con Slave 1 gửi dữ liệu về Master ta sẽ làm như sau:
Ví dụ 2 byte Header là 0x45 và 0xDE, quy ước lệnh gửi dữ liệu trở lại CMD = 1, CMD = 2 là yêu cầu xử lý dữ liệu của Master ( ví dụ Master yêu cầu Slave cho nhấp nháy đèn led, máy tính nhận dữ liệu và hiển thị....) có thể thêm nữa tùy bạn. Ví dụ dữ liệu của chúng ta có 3 byte dùng để truyền giá trị đếm được từ slave....
Checksum sẽ được tính : Checksum = (CMD + ID + Byte Data1 + Byte Data2 + Byte Data3)%100.
Vậy khung truyền thông như sau: 0x45; 0xDE; 0x02; 0x01; 0x12; 0x13; 0x85, Checksum.
Truyền ra từ Master như sau:
putchar(0x45);
putchar(0xDE);
putchar(0x02); //lệnh xử lý dữ liệu...
putchar(0x01); //slave 1 nhận dữ liệu
putchar(0x01); // byte dữ liệu cao
putchar(0x12); //byte dữ liệu giữa
putchar(0x13); //byte dữ liệu thấp
putchar((unsigned char)Checksum);
đến đây đã truyền được dữ liệu ra đến slave.
Còn Slave sẽ nhận dữ liệu. Dựa vào ID trùng với của mình rồi mới cho phép nhận dữ liệu. Dựa vào lệnh tương ứng mà Slave làm việc.....
Cách nhận dễ thôi. Tôi để các bạn tự tìm hiểu cho thêm thú vị.
Với máy tính. Coi như là một slave . máy tính sẽ hiển thị hoặc đưa lệnh cho Master cũng tương tự như trên.
Chúc thành công!n
ĐT: 0986 492 489
Tham khảo:
Comment
-
Nguyên văn bởi hungnp Xem bài viếtDù làm ở đâu thì cũng nên theo một tiêu chuẩn đã có sẵn và thiết thực khi áp dụng vào thực tế. Chẳng lẽ sinh viên thì có thể làm nhăng cuội sao?
Làm theo chuẩn là đúng. Tuy nhiên không ai thiết kế chuẩn dùng cho kết nối xa vào khoảng cách gần. Đã sinh ra chuẩn quốc tế thì chẳng lẽ nó là nhăng cuội? nó không được ứng dụng thực tế sao?. Bạn biết rằng đây là bài tập của sinh viên. Mà sinh viên làm bài tập nào đều có ứng dụng trong thực tế là nhỏ hay lớn thôi, thực tế có thể vài Km đến vài chục Km là chuyện thường nhưng nó sẽ áp dụng cho bài tập nâng cao cho sinh viên sau khi ra trường hoặc muốn tự mày mò để tìm hiểu thêm. Tôi đưa ra giải pháp ở đây là trong phạm vi năng lực của bạn trên. Vì trong nhà trường khoảng cách để thử mấy con kết nối với nhau cho giáo viên xem cũng chỉ vài mét đổ lại. Hoặc xa hơn thì 485 cũng không khác gì là mấy. Hơn nữa nếu bạn đã làm thực tế rồi bạn sẽ áp dụng được cách này đó. Chuẩn nào cũng vậy, chốt lại là để truyền dữ liệu và điều khiển. Tất cả đều phải có khung truyền thông.n
ĐT: 0986 492 489
Tham khảo:
Comment
-
Nguyên văn bởi minhhieu Xem bài viếtVới máy tính. Coi như là một slave . máy tính sẽ hiển thị hoặc đưa lệnh cho Master cũng tương tự như trên.
Comment
-
Chào hungnp!
Giao thức trên sử dụng giao thức của RS232. Cách mã hóa bit theo chuẩn 232 (phần cứng của IC đã làm việc này). RS232 đưa ra dữ liệu theo byte. Còn khung truyền thông tùy thuộc vào người thiết kế để có hiệu quả tốt nhất - việc này không bắt buộc theo chuẩn nào. Đây là phương pháp được sử dụng nhiều trong các hệ thống của nước ngoài cho mạng nhỏ và truyền thông RF không dây, phương pháp này tôi đã học được từ người Nhật và Hàn Quốc. Phương pháp áp dụng cho khung cố định. Để hiệu quả về mặt giảm thiểu thời gian chiếm đường truyền, người thiết kế có thể làm khung động...n
ĐT: 0986 492 489
Tham khảo:
Comment
-
Việc sử dụng RS232 để kết nối bus như bạn nói ở trên là tự dân chúng ta nghĩ ra thôi chứ chả ai bảo nó là một chuẩn cả? Bạn tìm được tài liệu công bố chính thức tôi xin đầu hàng vô điều kiện. Còn việc sử dụng cổng RS232 kết nối với Module RF như của bạn lại là một vấn đề khác. Cái này tôi cũng không rành vì chưa làm bao giờ.
Trong bài trên bạn dùng 2 byte liên tiếp để đánh dấu đầu của khung truyền, có nghĩa nếu bên nhận tìm thấy 2 byte đó liên tiếp nhau thì nó hiểu bắt đầu một khung truyền mới. Bạn có chắc chắn phần dữ liệu ngẫu nhiên của bạn sẽ không có 2 byte đó nằm sát nhau hay không? Nếu việc trùng lặp xẩy ra khung dữ liệu nhận được sẽ bị thiếu.
Comment
-
Mạng RS232 ở trên là một mạng như dạng Modbus. Việc trùng lặp xảy ra là có. Tuy nhiên rất ít, Checksum cũng chưa hẳn đã đúng nếu nó nhận được 2 byte bị đổi vị trí cho nhau... Ngay như với chuẩn RS232 cũng có khi bị nhận sai bit. Cũng tùy ứng dụng và tùy dạng dữ liệu ta sẽ thay đổi Header để hạn chế tối đa việc mất dữ liệu. Một số giao thức để giảm việc trùng lặp này người ta có thể dùng tới nhiều Header và có thể lên tới hàng chục Byte hay nhiều khung (mỗi khung có thể 24 byte) Header riêng, như các giao thức mạng internet chẳng hạn... Tuy nhiên ứng dụng của mình trong giới hạn truyền 4 con này với nhau việc xảy ra trùng lặp dữ liệu với Header là rất hiếm. Hơn nữa còn tùy thuộc vào việc truyền dữ liệu của bạn gì ở trên nữa để có thay đổi khung truyền thông tốt. Trên đây là tôi đưa ra gợi ý giải pháp cho bạn đó. Không có nghĩa là phải làm giống y nguyên như vậy.Last edited by minhhieu; 05-11-2009, 10:44.n
ĐT: 0986 492 489
Tham khảo:
Comment
-
Nếu nó là một chuẩn truyền thông công nghiệp thì không thể có một sai sót nào dù là nhỏ nhất hoặc ít xẩy ra. Nếu khi nhận bị lỗi khung truyền do tín hiệu điện, chất lượng IC... đó là một điều bình thường. Nhưng sai sót do phương thức mã hóa dữ liệu thì không thể chấp nhận được.
Với RS232 modbus chỉ sử dụng để kết nối điểm-điểm thôi. Còn kết nối mạng thì dùng rs485 và giao thức Master/Slave. ngoài ra Modbus còn có thêm Ethernet.
- Modbus sử dụng 2byte CRLF để đánh dấu frame nếu sử dụng ở mode ASCII, 2 byte này không bao giờ trùng vào phần dữ liệu vì phần dữ liệu tất cả được mã hóa dưới dạng ký tự '0':'9' và 'A':'F'. Còn ở mode RTU thì không cần byte đánh dấu mà dùng timer để tính timeout tùy thuộc vào tốc độ baud.
- Hy vọng sau một số bài trên bạn thanh48ctu có thể rút ra cho mình hướng giải quyết hợp lý.
Comment
-
Mình chỉ nói chung chung thôi. Ai cần thì ghép lại để thành một project cho riêng mình.
Compiler: CodevisionAVR V2.03.4.
Code sử dụng cho Atmega128. sử dụng cho slave. Master thì quá đơn giản rồi. Giao thức sử dụng là Modbus RTU. Baud 57600
1. Khởi tạo UART0.
#define XTAL 14745600
#define BAUD0 57600
UCSR0A=0x00;
UCSR0B=0x98;
UCSR0C=0x06;
UBRR0H=(unsigned char)(UBRR0>>8);
UBRR0L=(unsigned char)(UBRR0);
2. Khởi tạo timer1 để tính timeout 3.5char
/* ----------------------- Defines ------------------------------------------*/
#define F_CPU 14745600
#define UART_BAUD_RATE 57600
#define MB_TIMER_PRESCALER ( 1024 )
#define MB_TIMER_TICKS ( F_CPU / MB_TIMER_PRESCALER )
#define MB_50US_TICKS ( 20000 )
/* ----------------------- Static variables ---------------------------------*/
unsigned int usTimerOCRADelta;
//unsigned int usTimerOCRBDelta;
#define _BV(xbit) (1<<xbit)
#define OCIE1A 4
#define CS12 2
#define CS11 1
#define CS10 0
#define OCF1A 4
void Timer1Enable( void )
{
TCNT1 = 0x0000;
if( usTimerOCRADelta > 0 )
{
TIMSK |= _BV( OCIE1A );
OCR1A = usTimerOCRADelta;
}
TCCR1B |= _BV( CS12 ) | _BV( CS10 );
}
void Timer1Disable( )
{
/* Disable the timer. */
TCCR1B &= ~( _BV( CS12 ) | _BV( CS10 ) );
TIMSK &= ~( _BV( OCIE1A ) );
TIFR |= _BV( OCF1A ) ;
}
void Timer1Init( void )
{
unsigned int usTimerT35_50us;
if( UART_BAUD_RATE > 19200 )
{
usTimerT35_50us = 50; /* 1800us. */
}
else
{
usTimerT35_50us = ( 7 * 220000 ) / ( 2 * UART_BAUD_RATE );
}
usTimerOCRADelta =(unsigned int)( MB_TIMER_TICKS * usTimerT35_50us ) / ( MB_50US_TICKS );
TCCR1A = 0x00;
TCCR1B = 0x00;
TCCR1C = 0x00;
Timer1Disable( );
}
3. Sử dụng ngắt để nhận dữ liệu
// USART0 Receiver interrupt service routine
interrupt [USART0_RXC] void usart0_rx_isr(void)
{
char status,data;
status=UCSR0A;
data=UDR0;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
{
rx_buffer0[rx_wr_index0]=data;
if (++rx_wr_index0 == RX_BUFFER_SIZE0)
rx_wr_index0=0;
if (++rx_counter0 == RX_BUFFER_SIZE0)
{
rx_counter0=0;
rx_buffer_overflow0=1;
};
};
Timer1Enable();
}
4. Sử dụng ngắt TIM1_COMPA để nhận biết lúc nào khung dữ liệu kết thúc
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
unsigned int CRC16;
Timer1Disable();
//frame da nhan xong
if(rx_buffer0[ADDR_POS]==SLAVE_ADDR[0]) //so sánh địa chỉ
{
CRC16=(unsigned int)(rx_buffer0[rx_wr_index0-2]); //tính CRC16 của frame nhận được
CRC16 <<= 8;
CRC16 |= rx_buffer0[rx_wr_index0-1];
if(mbCRC16(rx_buffer0,rx_wr_index0-2) ==CRC16) //so sánh với checksum nhận được
{
// ID và Checksum OK. xử lý frame nhận được.
//các commandcode có giới thiệu trong tài liệu về modbus
}
}
else
{
}
rx_wr_index0=0;
}
5. Tính CRC16
flash unsigned char aucCRCHi[] = {
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40
};
flash unsigned char aucCRCLo[] = {
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7,
0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E,
0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9,
0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32,
0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D,
0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,
0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF,
0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1,
0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB,
0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97,
0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E,
0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89,
0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83,
0x41, 0x81, 0x80, 0x40
};
unsigned int mbCRC16( unsigned char * pucFrame, unsigned int usLen )
{
unsigned char ucCRCHi = 0xFF;
unsigned char ucCRCLo = 0xFF;
unsigned int iIndex;
while( usLen-- )
{
iIndex = ucCRCLo ^ *( pucFrame++ );
ucCRCLo = ( unsigned char )( ucCRCHi ^ aucCRCHi[iIndex] );
ucCRCHi = aucCRCLo[iIndex];
}
return ( unsigned int )( (ucCRCHi << 8) | ucCRCLo );
}
tài liệu tham khảo: www.modbus.org/docs/Modbus_Application_Protocol_V1_1b.pdf
Comment
Bài viết mới nhất
Collapse
-
Trả lời cho Hỏi về bơm màng bldcbởi vi van phamPhải xem cơ cấu bơm, chứ xem cơ cấu rotor, thì chỉ làm thầy bói xem voi.
-
Channel: Điện tử dành cho người mới bắt đầu
hôm nay, 08:19 -
-
Trả lời cho Xin hỏi về màn hình laptopbởi yname11vg, cám ơn bác...........
-
Channel: Thiết bị điện tử cá nhân
Hôm qua, 14:37 -
-
bởi khoine9899
Em chào các anh và mọi người.
Hiện em đang có 1 con bơm màng trong thiết bị y tế đang gặp tình trạng yếu dần hoặc ngừng hoạt động sau thời gian sử dụng
Sau khi tìm hiểu về thông tin của bơm trên mạng thì em được biết...-
Channel: Điện tử dành cho người mới bắt đầu
Hôm qua, 11:22 -
-
Trả lời cho Cần mọi người giúp mạch tạo sóng siêu âm máy rửabởi bqviet
-
Channel: Điện tử công suất
27-11-2024, 20:26 -
-
bởi Minhdai95Em chào mọi người, e đang sửa mạch tạo sóng siêu âm cho máy rửa mà chưa có tài liệu để tham khảo sửa, mọi người cho e xin tài liệu ạ...
-
Channel: Điện tử công suất
27-11-2024, 11:37 -
-
bởi pia2k1Cùng câu hỏi và cần được giải đáp thêm ạ...
-
Channel: Hướng dẫn sử dụng diễn đàn
27-11-2024, 11:28 -
-
Trả lời cho Công thức điện tửbởi mèomướpDạ thời thế giờ thay đổi theo hướng tích cực hơn rồi chú trung sĩ ạ. Kiến thức được chia sẻ ngày càng nhìu nên làm ăn gian dối ko còn dễ dàng như trước đâu ạ. Những thợ nhỏ rồi sẽ thành công nhân sản xuất đồ mới hết thay vì sửa chữa lặt vặt...
-
Channel: Tâm tình dân kỹ thuật
26-11-2024, 21:21 -
-
Trả lời cho Xin hỏi về màn hình laptopbởi mèomướpDạ cùng chuẩn tín hiệu thì chắc chắn là nhận ạ. Vì bản chất oled hay lcd thì đều phải có mạch chuyển đổi trên thanh gỗ rồi chuyển sang những chip xử lý hàng nghìn chân gắn trên những tab mỏng dính rồi mới ra các điểm ảnh theo hàng...
-
Channel: Thiết bị điện tử cá nhân
26-11-2024, 20:31 -
-
Trả lời cho Xin hỏi về màn hình laptopbởi yname11Ok , thanks bác đã chỉ...
-
Channel: Thiết bị điện tử cá nhân
26-11-2024, 15:06 -
-
bởi nguyendinhvanSau bao năm nghiên cứu cái dtvn. Tôi phát hiện công thức này. Các anh em xem đúng bao nhiêu phần trăm nhé !
Chập thì thay. Cháy thì tháo
Làm thì láo. Báo thì hay
May thì khoe. Rủi thì bỏ
Thành tích nhỏ. Báo thành to
Làm cho có. Báo chi li
Sai cả li. Báo...-
Channel: Tâm tình dân kỹ thuật
26-11-2024, 00:35 -
Comment