Thông báo

Collapse
No announcement yet.

Mạch đếm tần số.

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

  • Mạch đếm tần số.

    Em đang làm mạch đếm tần số, sử dụng chip Atmega 16. Về thuật toán thì em dùng Timer 1 là counter còn Timer 0 tạo khoảng đếm 0.1s. Code thì dựa trên code hướng dẫn của Atmel viết cho Atmega 168 ("AVR205 Frequency measurement made easy with Atmel tinyAVR and Atmel megaAVR"). Nhưng mà khi thử bằng Proteus thì sai. Nguồn vào 2.2k mà hiển thị tầm 1.8k trên màn hình LCD, nếu thay đổi tần số nguồn vào còn chả hiện gì . Thử build file code mẫu của Atmel cho Atmega 168 cũng chả đúng gì. Các bác cho em hỏi sai chỗ nào với ạ?
    Code:
    #include <avr/io.h>
    #include <compat/ina90.h>	// where _NOP, _CLI and _SEI are defined
    #include <avr/interrupt.h>
    #include <stdio.h>
    #include "myLCD.h"
    #include <util\delay.h>
    
    char dis[32];
    unsigned int	freq_cntr_result;
    unsigned int 	freq_cntr_freq_divd_by_10;
    unsigned int    x48_cnt_to_four_ints;
    
    //Prototypes
    void freq_cntr_start_measurement(void);
    unsigned int	freq_cntr_get_result(void);
    void	freq_cntr_clear_result(void);
    
    int main() 
    {
    	_SEI();						//! User to decide when to enable interrupts
    
    	TCCR1A=0x00;//Stop timer 0
    	TIFR	 |= (1<<TOV0);//Clear timer 0 overflow flag
    	TCNT1H  = 0x00; // clear counter upper 8 bits
    	TCNT1L  = 0x00; // clear counter lower 8 
    	TCNT0 = 0;
    	TIMSK = (1<<TOIE0);//Enable timer 0 overflow interrupt					
    	TCCR1B = (1<<CS12)|(1<<CS11);	// external clock source on T1 pin.Clock on the falling edge
    	
    
    	TCCR0 = (1<<CS02)|(1<<CS00); // divide by 1024, the largest divisor possible in MEGAx8
    	x48_cnt_to_four_ints = 0; 
    	
    		init_LCD();
    	while (1)
        {	
    		print_LCD("c");//Thử xem LCD có hoạt động ko?
    		_delay_ms(10);
    		clr_LCD();
    		
    
    				//User's code to be inserted here
    
    	if(freq_cntr_get_result() !=0) 
    		{
    
    		freq_cntr_result = freq_cntr_get_result();
    		}
    	sprintf(dis,"%d",freq_cntr_result);
    	print_LCD(dis);
    	_delay_ms(10);
    	}
    	return 0;
    }	//end of main
    
    unsigned int	freq_cntr_get_result(void)
    {
    	return freq_cntr_freq_divd_by_10;
    }
    
    ISR(TIMER0_OVF_vect) {
    
    		x48_cnt_to_four_ints++;
    		if(x48_cnt_to_four_ints == 3)TCNT0 = 0xff-13;
    		if(x48_cnt_to_four_ints >= 4)
    		{
    			TCCR1B = 0x00;	// stop FREQ_CNTR
    			TCCR0 = 0x00;
    
    //	ovf_test_and_return_result(); //places result into freq_cntr_freq_divd_by_10
    // Test TIFR for 16-bit overflow.  If overrange return  0xFFFF
    
    			if ((TIFR & (1<<TOV1)) !=0) {
    			// Test GATE_CNTR_OVF_FLAG for 16-bit overflow =  0xFFFF
    
    				freq_cntr_freq_divd_by_10 = 0xFFFF; // This is to return a OVF condition
    			}
    		else {
    			
    			freq_cntr_freq_divd_by_10 = TCNT1L+(TCNT1H<<8);
    
    			}
    		}
    
    }
    Click image for larger version

Name:	untitled.JPG
Views:	1
Size:	84.3 KB
ID:	1412808

  • #2
    Còn đây là code của Atmel viết cho Atmega 168
    #include <avr/io.h>
    #include <compat/ina90.h> // where _NOP, _CLI and _SEI are defined
    #include <avr/interrupt.h>


    char dis[30];
    unsigned int freq_cntr_result;
    unsigned int freq_cntr_freq_divd_by_10;
    unsigned int x48_cnt_to_four_ints;

    //Prototypes
    //void users_init(void);
    void freq_cntr_init(void);
    void freq_cntr_start_measurement(void);
    unsigned int freq_cntr_get_result(void);
    void freq_cntr_clear_result(void);

    int main()
    {

    freq_cntr_init();
    //! // User to insert their own code in this function, defined below.

    //users_init();
    _SEI(); //! User to decide when to enable interrupts

    freq_cntr_start_measurement(); // to measure frequency simply execute measure_frequency_via_interrupts();
    while (1)
    {

    //User's code to be inserted here

    if(freq_cntr_get_result() !=0)
    {

    freq_cntr_result = freq_cntr_get_result();
    freq_cntr_clear_result();

    //_NOP();//User's code to be inserted here

    freq_cntr_start_measurement(); // start another measurement

    }
    //_NOP();//User's code to be inserted here
    }

    return 0;
    } //end of main

    void freq_cntr_init(void)
    {
    TCCR1A=0x00;
    }

    void freq_cntr_start_measurement(void)
    {
    PCMSK2 |= (1<<PCINT21);
    PCICR |=(1<<PCIE2);
    }

    unsigned int freq_cntr_get_result(void)
    {
    return freq_cntr_freq_divd_by_10;
    }

    void freq_cntr_clear_result(void)
    {
    freq_cntr_freq_divd_by_10 = 0;
    }

    ISR(PCINT2_vect)
    {
    if ((PIND & (1<<PIND5)) !=0)
    {
    PCMSK2 = (0<<PCINT21);
    PCICR &= ~(1<<PCIE2);
    TIFR0 |= (1<<TOV0);//Clear gate overflow flag,timer 0 as gate
    // Enable FREQ_CNTR to count incoming signal on Megax8: PD5: timer 1 as counter

    TCNT1H = 0x00; // clear counter upper 8 bits
    TCNT1L = 0x00; // clear counter lower 8
    TCCR1B = (1<<CS12)|(1<<CS11); // select FREQ_CNTR input clock
    TCNT0 = 0;
    TIMSK0 = (1<<TOIE0);

    TCCR0B = (1<<CS02)|(1<<CS00); // divide by 1024, the largest divisor possible in MEGAx8
    x48_cnt_to_four_ints = 0; //Clear the x48 counter that counts 4 interrupts before closing gate
    }
    }


    ISR(TIMER0_OVF_vect) {

    x48_cnt_to_four_ints++;
    if(x48_cnt_to_four_ints == 3)TCNT0 = 0xff-13;
    if(x48_cnt_to_four_ints >= 4)
    {
    TCCR1B = 0; // stop FREQ_CNTR
    TCCR0B = 0;

    // ovf_test_and_return_result(); //places result into freq_cntr_freq_divd_by_10
    // Test TIFR for 16-bit overflow. If overrange return 0xFFFF

    if ((TIFR1 & (1<<TOV1)) !=0) {
    // Test GATE_CNTR_OVF_FLAG for 16-bit overflow = 0xFFFF

    freq_cntr_freq_divd_by_10 = 0xFFFF; // This is to return a OVF condition
    }
    else {

    freq_cntr_freq_divd_by_10 = TCNT1L+(TCNT1H<<8);

    }
    }

    }
    Vấn đề Timer1 có thể tràn với sóng có tần số cao và giải thuật của Atmel ở đó thì chỉ trả về 0xFFFF thôi, thì em nghĩ có thể dùng biến mềm khắc phục được. Nhưng mà khi giả lập với tần số chỉ 2.2k, vậy trong 0.1s chỉ đếm có 220 lần, so với khả năng của Timer1 thì nhỏ hơn rất nhiều mà lại sai thì em ko hiểu đươc? Cái anh chỉ bảo với ạ.

    Comment


    • #3
      mình không nghĩ vấn đề nằm ở timer. tại vì nếu như dùng timer1 16 bit giá trị tới 65535 giá trị. 1 xung bạn bắt chỉ cạnh lên hoặc cạnh xuống thì mình nghĩ bộ đếm của AVR dư dùng cho sampling time của bạn trong 10s. Mình nghĩ có thể Sampling time quá ngắn dẫn tới đọc không đúng thôi.

      Mobile: 0985158901
      Email:

      Comment


      • #4
        Cứ cắm mặt vào proteus thì đến mùa quýt mới khá lên đc.
        AVR đã quay trở lại: ATMEGA32: 66k, ATMEGA8A: 30k, ATMEGA48: 30k.
        Xem thêm tại Online Store ---> Click here
        Mob: 0982.083.106

        Comment


        • #5
          Cứ cắm mặt vào proteus thì đến mùa quýt mới khá lên đc.
          Chuẩn không cần phải chỉnh - mà chỉnh là hỏng luôn !
          Module RF chuyên dụng điều khiển, truyền dữ liệu, thiết kế đề tài, dự án điện tử - chuyển giao công nghệ... ĐT: 0904964977 - email: dientuqueduong@yahoo.com

          Comment


          • #6
            Phần lớn sai trong cái vụ này là thời gian lấy mẫu không chuẩn.
            Các cụ nhà mình cứ nghĩ việc tạo thời gian bằng mấy cái kiểu dùng ngắt timer và nạp mấy cái thanh ghi cho timer mà tạo được thời gian chuẩn dễ dàng theo cái kiểu tính chu kì thì còn khướt mà đòi nó chuẩn @@.

            Comment

            Về tác giả

            Collapse

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

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

            Collapse

            Đang tải...
            X