⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 countermeter.c

📁 一个用AVR做出的一个频率计
💻 C
字号:
/*************************************************
**
** 本程序根据Jesper的应用例子改编
** 源例子网页:http://www.myplace.nu/avr/countermeasures/index.htm
** CPU        ATmega16
** 晶振频率   4MHz
** 编译环境   AVR Studio 4.12.460  + GCC 3.4.3
** 程序修改   machao
** 时间      2005-12-07
**
*************************************************/
#define COUNTERMETER_C

#include <avr/io.h>
#include <avr/signal.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <stdlib.h>

//定义计数器控制引脚
#define CLEAR	PA6
#define OE_H	PA5
#define	OE_L	PA4


//#define F_CPU        4000000               		// 晶振频率 4MHz
#define CYCLES_PER_US ((F_CPU+500000)/1000000) 	// cpu cycles per microsecond 


// 数码管显示数据

#define SEG_a	0x01
#define SEG_b	0x02
#define SEG_c	0x04
#define SEG_d	0x08
#define SEG_e	0x10
#define SEG_f	0x20
#define SEG_g	0x40
#define SEG_dot	0x80


unsigned char digits[] = {
	(SEG_a|SEG_b|SEG_c|SEG_d|SEG_e|SEG_f),			// 0
	(SEG_b|SEG_c),									// 1
	(SEG_a|SEG_b|SEG_d|SEG_e|SEG_g),				// 2
	(SEG_a|SEG_b|SEG_c|SEG_d|SEG_g),				// 3
	(SEG_b|SEG_c|SEG_c|SEG_f|SEG_g),				// 4
	(SEG_a|SEG_c|SEG_d|SEG_f|SEG_g),				// 5
	(SEG_a|SEG_c|SEG_d|SEG_e|SEG_f|SEG_g),			// 6
	(SEG_a|SEG_b|SEG_c),							// 7
	(SEG_a|SEG_b|SEG_c|SEG_d|SEG_e|SEG_f|SEG_g),	// 8
	(SEG_a|SEG_b|SEG_c|SEG_d|SEG_f|SEG_g),			// 9	
	(SEG_a),										// mode 0 indicator	(Hz)
	(SEG_g),										// mode 1 indicator (kHz)
	(SEG_d),										// mode 2 indicator (MHz)
};


/****************************************************************************/


// timer 0 interrupt handles multiplex and refresh of the displays
//定时器T0的溢出中断用于刷新数码管
// timer is clocked at 62500 Hz

#define TI0_L		(256-125)		// 500 Hz -> 2 mS

volatile unsigned char 	active_led = 0;  //当前点亮的数码管

volatile unsigned long 	led_value = 0;	// four BCD nibbles
volatile unsigned char 	decimal_point = 0;
volatile unsigned char 	mode_setting = 0;



SIGNAL(SIG_OVERFLOW0)	//定时器T0溢出中断程序(16 uS中断一次)
{
	unsigned char a,b;
    //重新装载初值
    TCNT0 = TI0_L;
    //关闭所有数码管
    PORTA |= 0X07; 
	
	if (active_led == 5)
	{
		b = digits[10 + mode_setting];    //第6为数码管用于模式指示
	}
	else
	{
		a = led_value >> (( 4 - active_led ) * 4);
	
		b = digits[a & 0x0f];
	
		if (decimal_point == (4 - active_led) )
			b |= SEG_dot;
	}
    PORTB = b;
	//设置显示位置			
    PORTA = ((PORTA & 0Xf8)|active_led);
	active_led = (active_led+1) % 6;
}





/****************************************************************************/
/*  helpers  ****************************************************************/
/****************************************************************************/


void delay(unsigned short us) 
{
    unsigned short  delay_loops;
    register unsigned short  i;

    delay_loops = (us+3)/5*CYCLES_PER_US; // +3 for rounding up (dirty) 

	// one loop takes 5 cpu cycles 
    for (i=0; i < delay_loops; i++);
} 



//读16位计数值
unsigned int read_counters(void)
{
	unsigned int counter_value;

	// 读数据时关闭中断
	cli();
	//关闭数码管显示	
    PORTA |= 0X07;	
	//设置PORTB位输入	
    DDRB = 0X00;
	//置OE_H为低读取高8位	
    PORTA &= ~(1<<OE_H);
	asm volatile("nop");
	//1个脉冲锁存计数值
    PORTA |= (1<<OE_H);
	asm volatile("nop");	
    PORTA &= ~(1<<OE_H);
	asm volatile("nop");	
	//读高8位数据    
    counter_value = PINB;
    //置OE_H为高    		
    PORTA |= (1<<OE_H);
	counter_value <<= 8;	
	//置OE_L为低读取低8位
    PORTA &= ~(1<<OE_L);
	asm volatile("nop");
	//1个脉冲锁存计数值
    PORTA |= (1<<OE_L);
	asm volatile("nop");
    PORTA &= ~(1<<OE_L);
	asm volatile("nop");
    //读低8位数据  
    counter_value |= PINB ;  
    //置OE_L为高      
    PORTA |= (1<<OE_L);	
    //设置PORTB位输出
    DDRB = 0XFF;
	//使能数码管刷新
	sei();	
	return counter_value;
}



void capture(unsigned int compare)
{

	//清零外部计数器
    PORTA &= ~(1<<CLEAR);
	asm volatile("nop");
    //置清零为高
	PORTA |= (1<<CLEAR);
	//清计数值
    TCNT1H = 0;	
    TCNT1L = 0;

	//设置输出比较寄存器为所需值
    OCR1AH = compare >> 8;	
    OCR1AL = compare;
    //比较匹配时OC1A/OC1B 电平取反
    TCCR1A = (1<<COM1A0); //0x40;//
	//清比较匹配标志
    TIFR |= (1<<OCF1A);

	if (compare == 15625)
    {
		// start with fClk/256 (15625 Hz) and compare clear
        TCCR1B = (1<<WGM12)|(1<< CS12); //0x0C;//
    }
	else
    {
		// start with fClk/8 (500 kHz) and compare clear
        TCCR1B = (1<<WGM12)|(1<<CS11);  //0x0A;//
    }

	// wait for bit
    while ( ! (unsigned char) ( TIFR & (1<< OCF1A)) );
	// clear flags
	TIFR |= (1<<OCF1A);
	// counter input now enabled
	// for the specified time
	
	// wait again for bit
    while ( ! (unsigned char) ( TIFR & (1<< OCF1A)) );
	// stop timer
	TCCR1B = 0;
	// counter input disabled
}



/****************************************************************************/
/*  main  *******************************************************************/
/****************************************************************************/

int main(void) 
{
	int i,j;
	unsigned char dp,ms;
	unsigned long lv;
	unsigned int count;
    //设置PORTA为输出高电平
	DDRA  = 0XFF;	
    PORTA = 0XFF;
	//设置PORTB为输出高电平	
	DDRB  = 0XFF;	
    PORTB = 0XFF;
	//设置PORTD为输出高电平
	DDRD  = 0XFF;		
    PORTD = 0XFF;
    
	//设置定时器T0
	// 计数时钟为晶振频率64分频 周期为 = 1/(4000000/64 )-> 16 uS
    TCCR0 = (1<<CS01)|(1<<CS00);  //0x03;//
	//使能定时器T0溢出中断	
    TIMSK |= (1<<TOIE0);   
	//使能全局中断
	sei();


/*	输出比较寄存器初值在 fclk/8 (500 kHz, 2 uS) 下的门控值:
	
 	  500 	= 1 mS
	 5000 	= 10 mS
	50000	= 100 mS
	
	在 fclk/256 (15.625 kHz, 64 uS) :下的门控值:
	
 	15625  	= 1 S
*/
	// 清零16位计数器T1
    TCNT1H = 0;	
    TCNT1L = 0;
	// 设置输出比较寄存器初值为 200
    OCR1AH = 0;	
    OCR1AL = 200;
    //比较匹配时置位 OC1A/OC1B ( 输出高电平)
    TCCR1A = (1<<COM1A1)|(1<<COM1A0);   //0xC0;// 
	//启动定时器T1	
    TCCR1B = (1<<CS10);  //0x01;//

	//等待比较匹配标志位置位
    while ( ! (unsigned char) ( TIFR & (1<<OCF1A)) );
	//清楚标志
    TIFR |= (1<< OCF1A);    
	//定时器T1停止计数
    TCCR1B = 0;
	// compare bit no HI, start 
	// doing some useful work
	while (1)
	{
		//用最小的门控尝试
		capture(500);		// 1 mS
		//读取计数值		
		count = read_counters();
		dp = 3;		// 小数点位置
		ms = 2;		// 频率单位 MHz
		
		if (count < 4096)     // 小于 4.096 MHz
		{
			//尝试下一个门控值
			capture(5000);		// 10 mS
			//读取计数值	
			count = read_counters();
			dp = 4;		// 小数点位置
			ms = 2;		// 频率单位 MHz

			if (count < 4096)	// 小于 409.6 kHz
			{
				// 尝试下一个门控值
				capture(50000);	// 100 mS
				//读取计数值		
				count = read_counters();
				dp = 2;		// 小数点位置
				ms = 1;		// 频率单位 kHz
			
				if (count < 4096)	//  小于 40.96 kHz
				{
					// 尝试下一个门控值
					capture(15625);		// 1 S
					//	读取计数值	
					count = read_counters();
					dp = 0;		// 小数点位置
					ms = 0;		// 频率单位 Hz
				}
			}
		}
		
		//将二进制16位计数值转换位BCD码
		lv = 0;
		for (j=0;j<8;j++)
		{
			i = count % 10;
			lv >>= 4;
			lv |= ((unsigned long)i << 28);
			count /= 10;
		}

		//设置显示参数
		decimal_point = dp;
		mode_setting  = ms;
		led_value     = lv;
	} 

}



⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -