Thông báo

Collapse
No announcement yet.

hothothot Tạo đường truyền BUS giữa 4 atmega 16

Collapse
X
 
  • Lọc
  • Giờ
  • Show
Clear All
new posts

  • hothothot Tạo đường truyền BUS giữa 4 atmega 16

    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.

  • #2
    Sử dụng giao thức modbus master/slave RTU hoặc ASCII, kết nối bằng chuẩn truyền thông RS485. Chịu khó search sẽ có cả tài liệu và ví dụ về cái này. rất nhiều.

    Comment


    • #3
      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


      • #4
        Dù 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?

        Comment


        • #5
          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


          • #6
            Nguyên văn bởi hungnp Xem bài viết
            Dù 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?
            Chào Hungnp!
            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


            • #7
              Vậy minhhieu xin cho hỏi, giao thức truyền nhận dữ liệu và mã hóa dữ liệu ở trên bạn sử dụng giao thức truyền thông nào?

              Comment


              • #8
                Nguyên văn bởi minhhieu Xem bài viết
                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.
                Tại sao máy tính trong trường hợp này lại có thể là slave được? Nó phải là Master của Master chứ nhỉ?.

                Comment


                • #9
                  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


                  • #10
                    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


                    • #11
                      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


                      • #12
                        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


                        • #13
                          Bạn hungnp có thể viết một đoạn code truyền thông cũng như sơ đồ giao tiếp cho thanh48ctu được không, nhân đây anh em cũng học hỏi thêm từ bạn.
                          n
                          ĐT: 0986 492 489

                          Tham khảo:

                          Comment


                          • #14
                            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


                            • #15
                              cho e hỏi các pác về kịch bản truyền nhận của master và slave như thế nào để khỏi có sự xung đột đường truyền bus? ví dụ để tránh 2 con slave hoặc 1 con slave và 1 con master cùng truyền 1 lúc.

                              Comment

                              Về tác giả

                              Collapse

                              thanh48ctu Tìm hiểu thêm về thanh48ctu

                              Bài viết mới nhất

                              Collapse

                              Đang tải...
                              X