Thông báo

Collapse
No announcement yet.

Các vấn đề cơ bản về I/O Port (Revised 12/02/09)

Collapse
This is a sticky topic.
X
X
 
  • Lọc
  • Giờ
  • Show
Clear All
new posts

  • duc thang
    replied
    Điện trở kéo lên Rpu hình như chỉ chọn cho cả port, không chọn riêng từng pin được ?
    Tuy nhiên control Rpu còn có 2 ngả là WDx và WPx tác động lên từng pin.

    Leave a comment:


  • zemen
    replied
    tóm lại

    Sau khi coi lại về cổng port của AVR thì zemen thấy cần nhớ các điểm chính:
    - Dùng 3 thanh ghi cho mỗi port, gồm th.ghi chiều (DDR), th.ghi mức (PORT) và th.ghi đọc (PIN)
    - Port có chức năng Read-Modify-Write (Đọc-sửa-xoá)
    - Có thể xử lí từng chân của port (tức là xử lí từng bít của các thanh ghi)
    - Mỗi chân của port có thể có các trạng thái vào, ra và tổng trở cao tuỳ theo giá trị của 3 thanh ghi port
    - Các chân của port đều có diode bảo vệ quá áp
    - Có thể chọn điện trở kéo lên Rp cho từng chân của port
    - Dòng cấp và nhận cho mỗi chân đạt đến 20mA
    - 1 chân vdk, khi dùng các chức năng khác nếu có (như ADC, SPI,...) thì không dùng đc chức năng vào/ra bình thường của port

    Leave a comment:


  • VNarmy
    replied
    Định hướng chút: Đây là box chủ yếu tập trung vào hướng dẫn, làm tutor, đồng thời luồng này chủ yếu tập trung vào vấn đề về các port I/O chung. Vì vậy các bạn khi thảo luận nên tập trung vào chủ đề chính.
    @KHz: Bạn muốn làm TUT về timer là rất hay. Bạn có thể soạn trước file dạng word rồi gửi cho tôi để tôi đóng góp thêm trước khi đưa lên đc ko?

    Leave a comment:


  • Kilodeth
    replied
    Nguyên văn bởi sun_rise Xem bài viết
    Cái này chính là con led7seg chứ là cái gì. Xem các bài viết về thuật toán quét led7seg là ok.
    Chúc vui!
    Bạn nhầm ở hai vấn đề:
    1. mình đặt vấn đề chứ không hỏi
    2. có lẽ bạn nhầm mạch trên với mạch này?


    hay mạch này?


    hơi ít vui

    Leave a comment:


  • sun_rise
    replied
    Cái này chính là con led7seg chứ là cái gì. Xem các bài viết về thuật toán quét led7seg là ok.
    Chúc vui!

    Leave a comment:


  • Kilodeth
    replied



    Bạn giúp cấu hình cho các chân và giải thuật quét cho mạch này với, một cách để hiểu thêm về I/O port AVR.

    Thanks n' best regards

    Leave a comment:


  • Các vấn đề cơ bản về I/O Port (Revised 12/02/09)

    Giới thiệu chung

    Các cổng vào ra của AVR đều có tính năng true Read – Modify – Write khi sử dụng chúng như các cổng vào ra thường. Nghĩa là chiều vào/ra của một chân có thể thay đổi riêng biệt mà không làm ảnh hưởng tới chiều vào/ra của các chân khác bằng các lệnh SBI và CBI. Tương tự với giá trị out ra (khi cấu hình cổng là cổng output) cũng như là việc cho phép hay không cho phép trở treo ở các chân. Bộ đệm ra có đặc tính lái dòng đối xứng với cả việc hút và tạo dòng. Bộ lái dòng đủ mạnh để điều khiển LED (20 mA theo như [1]). Các chân có thể chọn điện trở treo một cách độc lập. Tất cả các chân đều có diode bảo vệ. Dễ dàng thấy từ hình vẽ dưới các diode này sẽ bảo vệ các chân khỏi việc điện áp quá lớn từ ngoài ảnh hưởng đến vi điều khiển. Khi điện áp lớn hơn Vcc hoặc nhỏ hơn GND nó sẽ bị hạn biên về giá trị Vcc hoặc GND.



    Mỗi PORT chiếm 3 địa chỉ trong vùng bộ nhớ vào/ra cho thanh ghi dữ liệu PORT, thanh ghi chiều vào/ra của PORT và PORT INPUT PINS. Riêng PORT INPUT PINS là bộ nhớ chỉ đọc. Thêm vào đó, bit Pull – Up Disable, PUD chứa trong thanh ghi SFIOR sẽ không cho phép điện trở pull up khi set bit này.

    Sơ đồ khối của cổng


    Cấu hình cho PORT

    Mỗi PORT có 3 thanh ghi chứa các bit PORTxn, DDxn và PINxn (x=A..D, n= 0..7) nằm trong các thanh ghi tương ứng PORTx, DDRx và PINx.
    Các bit DDxn trong thanh ghi DDRx cho phép chọn chiều của một chân trong PORT. Khi bit này set thì chân đó sẽ được cấu hình là chân output và khi bit này clear thì chân đó sẽ được cấu hình là chân input.
    Khi bit PORTxn được set và chân được cấu hình là input thì điện trở treo sẽ được kích hoạt. Để tắt điện trở treo nội, bit PORTxn phải được xoá hoặc chân được cấu hình là chân output.
    Khi chuyển giữa trạng thái tri-state ({DDxn,PORTxn}=0b00) và output high ({DDxn,PORTxn}=0b11) cần phải qua một trạng thái trung gian là cho phép pull-up ({DDxn,PORTxn}=0b10) hoặc output low ({DDxn,PORTxn}=0b01). Khuyến nghị là nên chọn trạng thái trung gian là cho phép pull up.
    Tương tự khi chuyển giữa trạng thái pull up và output low.



    Đọc giá trị tức thời tại các chân VĐK

    Mặc dù cùng là VĐK của Atmel nhưng khác với họ AT89xx, dòng AVR qui định rõ ràng và tách bạch nhiệm vụ đọc ghi của từng chân trong cổng thông qua thanh ghi DDRx. Tuy nhiên, AVR cũng rất mềm dẻo trong việc đọc giá trị tức thời của các chân mà không cần phải biết chân đó đang dùng là chân vào hay ra nhờ vào thanh ghi PINxn. Giá trị trên thanh ghi PINxn chính là giá trị tức thời của chân n (n=0..7) ở port x (x=A..D).
    Ở đầu vào thanh ghi PINx có sử dụng các bộ chốt D-trigger giúp ổn định giá trị đầu vào. Tuy nhiên nó cũng gây ra sự trễ nho nhỏ khi đọc giá trị. Do vậy, khi đọc giá trị gửi ra trong phần mềm thì cần có một lệnh trễ giữa lệnh gửi ra và lệnh đọc vào.

    Một số chú ý:

    - Riêng PortA được cấp nguồn từ AVCC. Vì vậy khi sử dụng PortA cần nối AVCC với +VCC. Trong trường hợp dùng chức năng ADC của PortA thì AVCC nên nối với +VCC thông qua mạch lọc.

    Một vài ví dụ sử dụng cổng vào ra

    Một ví dụ cơ bản đó là quét bàn phím:

    Code:
    /* 
      4x4 Keypad Demo
    
      CodeVisionAVR C Compiler
      (C) 2000-2007 HP InfoTech S.R.L.
      www.hpinfotech.ro
    
      Chip: ATmega8515
      
      PLEASE MAKE SURE THAT THE CKSEL0..3 FUSE
      BITS ARE PROGRAMMED TO USE THE EXTERNAL
      CLOCK SOURCE OF THE STK500 AND NOT
      THE INTERNAL 1MHz OSCILLATOR.
      The ATmega8515 chip comes from the factory
      with CKSEL0..3 fuse bits set to use the
      internal 1 MHz oscillator.
    
      Connect the keypad matrix as follows:
       
      [STK500 PORTD HEADER]   [KEYS]  R1
      1 PD0 -----0----1----2----3----~~~~~---o+5V
                 |    |    |    |     R2   |
      2 PD1 -----4----5----6----7----~~~~~-
                 |    |    |    |     R3   |
      3 PD2 -----8----9----10---11---~~~~~-
                 |    |    |    |     R4   |
      4 PD3 -----12---13---14---15---~~~~~-
             D1  |    |    |    |
      5 PD4 -|<|-     |    |    |
             D2       |    |    |
      6 PD5 -|<|------     |    |
             D3            |    |
      7 PD6 -|<|-----------     |  R1..R4=10k..47k
             D4                 |
      8 PD7 -|<|----------------   D1..D4=1N4148
       
      Use an 2x16 alphanumeric LCD connected
      to PORTC as follows:
    
      [LCD]   [STK500 PORTC HEADER]
       1 GND- 9  GND
       2 +5V- 10 VCC  
       3 VLC- LCD contrast control voltage 0..1V
       4 RS - 1  PC0
       5 RD - 2  PC1
       6 EN - 3  PC2
      11 D4 - 5  PC4
      12 D5 - 6  PC5
      13 D6 - 7  PC6
      14 D7 - 8  PC7
    */
    
    #asm
        .equ __lcd_port=0x15
    #endasm
    
    #include <lcd.h>
    #include <stdio.h>
    #include <delay.h>
    #include <mega8515.h>
    
    // quartz crystal frequency [Hz]
    #define F_XTAL 3686400L
    // PIND0..3 will be row inputs
    #define KEYIN PIND
    // PORTD4..7 will be column outputs
    #define KEYOUT PORTD
    // used for TIMER0 count initialization
    #define INIT_TIMER0 TCNT0=0x100L-F_XTAL/64L/500L
    #define FIRST_COLUMN 0x80
    #define LAST_COLUMN 0x10
    
    typedef unsigned char byte;
    // store here every key state as a bit,
    // bit 0 will be KEY0, bit 1 KEY1,...
    unsigned keys;
    // LCD display buffer
    char buf[33];
    
    // TIMER 0 interrupt at every 2 ms
    interrupt [TIM0_OVF] void timer0_int(void)
    {
    static byte key_pressed_counter=20;
    static byte key_released_counter,column=FIRST_COLUMN;
    static unsigned row_data,crt_key;
    // reinitialize TIMER0
    INIT_TIMER0;
    row_data<<=4;
    // get a group of 4 keys in in row_data
    row_data|=~KEYIN&0xf;
    column>>=1;
    if (column==(LAST_COLUMN>>1))
       {
       column=FIRST_COLUMN;
       if (row_data==0) goto new_key;
       if (key_released_counter) --key_released_counter;
       else
          {
          if (--key_pressed_counter==9) crt_key=row_data;
          else
             {
             if (row_data!=crt_key)
                {
                new_key:
                key_pressed_counter=10;
                key_released_counter=0;
                goto end_key;
                };
             if (!key_pressed_counter)
                {
                keys=row_data;
                key_released_counter=20;
                };
             };
          };
       end_key:;
       row_data=0;
       };
    // select next column, inputs will be with pull-up
    KEYOUT=~column;
    }
    
    // test if a key was pressed
    unsigned inkey(void)
    {
    unsigned k;
    if (k=keys) keys=0;
    return k;
    }
    
    void init_keypad(void)
    {
    // PORT D initialization
    // Bits 0..3 inputs
    // Bits 4..7 outputs
    DDRD=0xf0;
    // Use pull-ups on bits 0..3 inputs
    // Output 1 on 4..7 outputs
    PORTD=0xff;
    // Timer/Counter 0 initialization
    // Clock source: System Clock
    // Clock value: 57.600 kHz
    // Mode: Normal top=FFh
    // OC0 output: Disconnected
    TCCR0=0x03;
    INIT_TIMER0;
    OCR0=0x00;
    // External Interrupts are off
    MCUCR=0x00;
    EMCUCR=0x00;
    // Timer 0 overflow interrupt is on
    TIMSK=0x02;
    #asm("sei")
    }
    
    main() {
    unsigned k;
    init_keypad();
    lcd_init(16);
    lcd_putsf("CVAVR Keypad");
    // read keys and display key code
    while (1)
          {
          lcd_gotoxy(0,1);
          if (k=inkey())
             {
             sprintf(buf,"Key code=%Xh",k);
             lcd_puts(buf);
             }
          else lcd_putsf("NO KEY        ");
          delay_ms(500);
          }
    }
    [1] ATMEGA8535 datasheet

    Rất mong nhận được sự đóng góp, thảo luận của mọi người để tôi có thể hoàn thiện vấn đề này.
    Last edited by VNarmy; 12-02-2009, 13:04.

Về tác giả

Collapse

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

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

Collapse

Đang tải...
X