Thông báo

Collapse
No announcement yet.

TẠi sao khi sỬ dỤng 2 kÊnh adc trong atmega32

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

  • TẠi sao khi sỬ dỤng 2 kÊnh adc trong atmega32

    Chả hiểu tại sao khi sử dụng cùng 2 kênh ADC trong ATMEGA32 thì chỉ có 1 kênh hoạt động kênh còn lại chạy theo kênh kia.

    Cụ thể là dùng 2 loại cảm biến ánh sáng và nhiệt độ đưa vào 2 kênh sau đó phát ra LCD thì nó hiện kết quả chỉ đúng cho 1 kênh, kênh còn lại thì lại hiện kết quả phụ thuộc. Ví dụ như thông số nhiệt độ là 32 (ở kênh ADC1), ánh sáng là 50 (ở kênh ADC0) thì khi hiện lên LCD nó hiện là 32 32 thay đổi thông số nhiệt độ thì thông số ánh sáng trên LCD chạy theo còn thay đổi thông số ánh sáng thì thông số trên LCD vẫn nằm yên.Chả hiểu làm sao.

    Nhưng khi tách ra làm từng kênh thì nó lại chạy đúng.

    Mình dùng winavr và protues mô phỏng.
    Mong bà con cô bác giúp hộ.


    code mình viết:

    #include <avr/io.h>
    #include <util/delay.h>
    #define AREF_MODE 0
    #define AVCC_MODE (1<<REFS0)
    #define INT_MODE (1<<REFS1)|(1<<REFS0)
    #define ADC_VREF_TYPE AREF_MODE
    uint16_t read_adc(unsigned char adc_channel);
    uint16_t nhietdo,dosang,A[15];
    int main(){
    ADCSRA=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1);
    ADMUX=ADC_VREF_TYPE;
    //khoi dong chuyen doi ADC
    init_LCD();
    clr_LCD();
    while(1){
    dosang=read_adc(0)/2;
    lcd_putnum(dosang,2,9);
    _delay_us(1000);
    nhietdo=(read_adc(1)-2)/2;
    lcd_putnum(nhietdo,2,13);
    _delay_us(1000);
    }
    }
    uint16_t read_adc(unsigned char adc_channel) {
    ADMUX|=adc_channel;
    ADCSRA|=(1<<ADSC);
    //wait for conversion complete
    loop_until_bit_is_set(ADCSRA,ADIF);
    //while (!(ADCSRA & (1<<ADIF)));
    return ADCW;
    }
    Last edited by ptnksmart; 15-10-2010, 00:48.

  • #2
    Mình ko check code nhưng chỉ muốn nói với bạn là chắc chắn bạn nhầm đâu đó. Mình vẫn hay ADC có sao đâu nhỉ_Muốn đúng thì khi thiết lập phải chuẩn, sau đó để đọc ADC kênh nào đó thì đọc,đọc lần lượt từng kênh 1. Thế thôi.


    Add: 97 Quán Nam - Lê Chân - Hải Phòng.
    Tel: 031 518648 Phone: 0904 283 505

    Comment


    • #3
      Không biết bạn đã từng làm thử 2 kênh ADC chưa thì chỉ giáo hộ.Chứ theo mình thấy thì làm từng kênh thì nó ok nhưng ghép hai kênh thì nó lại chạy theo kiểu kênh nọ phụ thuộc kênh kia thì sai ở chỗ nào.
      Bạn biết thì giải thích hộ chứ nói chung chung như vậy thì mình cần gì phải hỏi nữa.

      Comment


      • #4
        Hàm read_adc bạn viết không ổn rồi. Sửa lại như sau:

        Code:
        uint16_t read_ADC(uint8_t channel)
        {               
            // Analog channel selection
            ADMUX = (ADMUX & 0xF0) | (channel & 0x0f);
            // Start conversion
            ADCSRA |= _BV(ADSC);
            // Wait until conversion complete
            while( bit_is_set(ADCSRA, ADSC) );
            return ADCW;    
        }
        Last edited by hungnp; 15-10-2010, 14:22. Lý do: Mình nhầm một tí.

        Comment


        • #5
          Theo mình thấy thì hàm của bạn sửa lại nó còn tệ hơn. Trên LCD không những thông số của phần nhiệt độ nó không hiện ra (w67) mà thông số của phần ánh sáng cũng chả hiện nốt.Thông số phần nhiệt độ lúc này lại nằm bên phần thông số ánh sáng và thay đổi thông số nhiệt độ trên cảm biến thì thông số phần ánh sáng lại chạy theo.
          Để cái cũ dù sao cũng còn 1 cái đúng còn cái của bạn cả hai cái đều hiển thị sai cả.
          Nhưng dù sao cũng cảm ơn bạn đã nhiệt tình.
          Theo mình thấy thì làm cách nào sao khi đọc xong giá trị ở mỗi kênh ADC thì nó lại trở về vị trí như ban đầu trước khi ta sử dụng ADC có như vậy nó mới đúng được. Nhưng mà chưa biết sửa làm sao.

          Comment


          • #6
            Mình up cho các bạn tham khảo một ví dụ về ATMEGA8 kết nối với 2 cảm biến nhiệt độ ở 2 kênh khác nhau. và gửi dữ liệu ra cổng USART.
            Compiller: AVRSTUDIO 4.
            Simulator: Proteus 7.5SP3
            Mình mô phỏng với bản Proteus 7.6SP4 thì bị lỗi. Chắc cái 7.6SP4 của mình có vấn đề.LM335.zip

            Comment


            • #7
              Có bà con nào biết chỉnh sửa sao không? Không biết cái này nó chạy gì đâu á. Mình chỉ có thể sửa để nó hiện lên đúng cả hai giá trị nhưng sau đó thì chỉ có 1 giá trị thay đổi khi thông số cảm biến thay đổi còn giá trị còn lại vẫn đứng im dù thông số cảm biến có thay đổi.Cách sửa là dùng ngắt toàn cục.Tiến thêm một bước rồi còn một bước nữa là tới đích có bà con nào giúp mình với.

              Comment


              • #8
                ADMUX|=adc_channel;
                Bắt đầu vào chương trình bạn đọc kênh 0 thì ADMUX|=0 nên ADMUX=0;
                Sau đó đọc kênh 1: ADMUX|=1 thì ADMUX=1;
                Tiếp theo bạn lại đọc ở kênh 0: Trước đó ADMUX=1 nên ADMUX=0|1 = 1. Có nghĩa từ đây bạn chỉ đọc được giá trị từ kênh 1 mà không đọc được giá trị kênh 0 vì ADMUX luôn bằng 1.
                Tóm lại chương trình chỉ đọc được kênh 0 duy nhất 1 lần khi bật nguồn. Còn sau đó chỉ đọc kênh 1.
                Bạn thay lệnh trên bằng lệnh này đi: ADMUX|=(ADMUX & 0xF0) | (adc_channel & 0x0F);

                Comment


                • #9
                  uh thì mình cũng nghĩ vậy nên đang rối trí không biết tính sao. Lúc đầu định cho ngắt toàn cục sau mỗi lần đọc rồi cho nó khởi động lại nhưng vẫn không ăn thua.Theo mình nghĩ cách tốt nhất là làm sao mỗi lần đọc xong thì ADMUX phải trở về như lúc ban đầu nó mới có kết quả tồng quát.Để tối nay mình check thử code của bạn có đúng với ý đồ của mình không. Chứ nhìn sơ qua chắc cách giải quyết của bạn có hiệu quả đấy.
                  Cảm ơn bạn nhiều nha.

                  Comment


                  • #10
                    Đứt đuôi còn nòng nọc rồi bạn ơi! Hình như chúng ta nghĩ sai hướng sao ý.Nó vẫn y trạng thái cũ.
                    Ý tưởng của bạn có thể là một trong những chìa khóa giải quyết vấn đề để mình xem lại thử xem.

                    Comment


                    • #11
                      Nếu không được bạn chuyển code vào mail: hungnp82@gmail.com mình sẽ check giúp bạn.

                      Comment


                      • #12
                        Không cần nữa đâu bạn ơi! Code bạn viết mình đã check rồi! Nó không phù hợp.
                        Mình đã có một cách giải quyết đơn giản hơn nhiều mà lâu nay không nghĩ ra.Chỉ cần thêm một dòng code nữa vào chương trình chính là ok thôi.

                        #include <avr/io.h>
                        #include <util/delay.h>
                        #include <avr/math.h>
                        #include <myLCD.h>
                        #include <avr/interrupt.h>
                        #include <stdio.h>
                        #define KEYPAD_DDR DDRB
                        #define KEYPAD_PORT PORTB
                        #define KEYPAD_PIN PINB
                        #define AREF_MODE 0
                        #define AVCC_MODE (1<<REFS0)
                        #define INT_MODE (1<<REFS1)|(1<<REFS0)
                        #define ADC_VREF_TYPE AREF_MODE

                        uint16_t key;
                        uint16_t read_adc(unsigned char adc_channel);
                        uint16_t checkpad(),i,keyin,keyout;
                        uint16_t check();
                        uint16_t n,m,T,a,b,c,k,x,nhietdo,dosang,A[15];
                        int main(){
                        uint16_t m,T,H,P,Q,T1,T2,a,b,c,k,A[15];
                        //---khai bao huong cho cac chan ket noi keypad
                        DDRD=0xFF;
                        PORTD=0x00;
                        KEYPAD_PORT=0x0F; //*
                        KEYPAD_DDR=0xF0; //*
                        //*********************************************
                        ADCSRA=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1);
                        ADMUX=ADC_VREF_TYPE;

                        //khoi dong chuyen doi ADC
                        init_LCD();
                        clr_LCD();
                        while(1){
                        n=0;
                        T=0;
                        a=0;
                        b=0;
                        c=0;
                        dosang=read_adc(0)/2;
                        lcd_putnum(dosang,2,9);
                        _delay_us(1000);
                        nhietdo=(read_adc(1)-2)/2;
                        lcd_putnum(nhietdo,2,13);
                        _delay_us(1000);
                        ADMUX=0;

                        }
                        }

                        uint16_t read_adc(unsigned char adc_channel) {
                        ADMUX|=adc_channel;
                        ADCSRA|=(1<<ADSC);
                        //wait for conversion complete
                        //loop_until_bit_is_set(ADCSRA,ADIF);
                        while (!(ADCSRA & (1<<ADIF)));
                        return ADCW;
                        }

                        Comment


                        • #13
                          Nếu không phải đọc kênh 0 và kênh 1 mà là kênh 1 và kênh 3 chẳng hạn. Code của bạn sẽ vẫn sai. Cứ nghiên cứu thêm nữa đi.

                          Comment


                          • #14
                            mình nghĩ rồi! Đoạn chương trình mình đưa lên chỉ là một phần nhỏ trong chương trình của mình thôi!Thật sự thì đoạn code của bạn đã đưa mình không thể sử dụng trong chương trình của mình được.Còn việc sử dụng kênh ADC nào không quan trọng.Bởi vì theo đoạn code mình viết thì sau khi đọc xong từng kênh thì ADMUX sẽ trở về giá trị 0 như lúc ban đầu và chỉ cần lệnh ADMUX|=adc_channel;tức là or 0 với giá trị adc_channel (tức là từ 0 đến 7 hay là 00000 - 00111) thì giá trị ADMUX sẽ tương ứng như vậy.Lúc đó nó đọc đúng thôi.Và điều này mình cũng đã check và chạy hoàn chỉnh rồi bạn ạ.
                            Chỉ có cái là trong trường hợp đọc ADC theo kiểu so sánh thì nó mới khác một ít.

                            Comment


                            • #15
                              Trường hợp này lúc trước mình cũng gặp và giải quyết được rồi.
                              Đơn giản là khi thực thi chương trình ADC và cho hiển thị kết quả do quá trình chọn kênh diễn ra nhanh trong khi
                              chương trình thực thi và cho hiển thị chưa hoàn tất nên xảy ra hiện tượng trùng kênh.
                              Cách giải quyết:
                              Bạn thêm hàm delay khoảng 1ms, nếu không được thì tăng lên chút xíu là ok.
                              ví dụ trong code của bạn:
                              ADMUX|=adc_channel;
                              delay_ms(1);
                              - Còn code của mình đây:
                              void Channel_Select(unsigned char ch)
                              {
                              ADMUX=ch|ADC_VREF_TYPE;
                              _delay_us(10); // Phải có delay này, nếu không sẽ bị trùng kênh
                              }

                              Comment

                              Về tác giả

                              Collapse

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

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

                              Collapse

                              Đang tải...
                              X