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

📄 main.c

📁 基于AVR的数字频率计
💻 C
字号:
#include <avr/io.h>
#include <avr/iom8.h>
#include <avr/signal.h>
#include <avr/interrupt.h>
#include <stdint.h>
#include <avr/wdt.h>
#include <util/delay.h>
#include <stdio.h>

/*----------------------常用参数定义-------------------*/

#define P0 0
#define P1 1
#define P2 2
#define P3 3
#define P4 4
#define P5 5
#define P6 6
#define P7 7

#define FREQ 8
#define uint unsigned int
#define uchar unsigned char

/*----------------------某些端口操作-------------------*/

#define SET_DOOR PORTB|=_BV(P1)
#define CLR_DOOR PORTB&=~_BV(P1)

#define SET_CLEAR PORTB|=_BV(P2)
#define CLR_CLEAR PORTB&=~_BV(P2)

/*----------------------1602定义-------------------*/

#define SET_LCD_RS PORTD|=_BV(P2)
#define CLR_LCD_RS PORTD&=~_BV(P2)

#define SET_LCD_RW PORTD|=_BV(P3)
#define CLR_LCD_RW PORTD&=~_BV(P3)

#define SET_LCD_E  PORTD|=_BV(P4)
#define CLR_LCD_E  PORTD&=~_BV(P4)

#define SET_74LS595_SHIFT PORTB|=_BV(P0)
#define CLR_74LS595_SHIFT PORTB&=~_BV(P0)

#define SET_74LS595_DI PORTD|=_BV(P6)
#define CLR_74LS595_DI PORTD&=~_BV(P6)

#define SET_74LS595_CLK PORTD|=_BV(P7)
#define CLR_74LS595_CLK PORTD&=~_BV(P7)

void LCD_ON(void);     //启动LCD
void LongConvertToChar(unsigned long WD);
void LCDInit(void);
void WriteDataLCD(unsigned char WDLCD);
void WriteCommandLCD(unsigned char WCLCD);
void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData);
void DisplayListChar(unsigned char X, unsigned char Y,unsigned char *DData);
void WriteDataTo595(unsigned char WDLCD);

const unsigned char  Owner[] = {"Hello World !!!"};
const unsigned char uctech[] = {"INPUT FREQUENCE:"};
const unsigned char   Init[] = {"Initialization."};
unsigned char net[16] =         {"Axin & Cornsoup"}; 
unsigned char Net_Pointer=0;//net[] 的指针

unsigned char Timer1_Counter_H=0;
unsigned char Timer1_Counter_L=0;
unsigned long Frequence=0;
unsigned char T2_OV_Time=1;  //T2溢出对应的时间
unsigned char T1_OV_Times=0; //T1溢出次数


/*----------------------串口定义-------------------*/

unsigned char SetPrintfConvertMode=0; //使用printf作其他转换,并非输出到UART

void Uart_Init(void);

int System_putchar(char c, FILE *stream);
int System_getchar(FILE *stream);

FILE mystd = FDEV_SETUP_STREAM(System_putchar, System_getchar,_FDEV_SETUP_RW);

/*----------------------常用函数定义------------------*/

void delay_nms(unsigned int ms)                //N ms延时函数
{
	uint i;
	for(i=0;i<ms;i++)
		_delay_loop_2(FREQ*250);
}

/*----------------------系统初始化函数定义------------------*/

void IO_INIT(void);


/////////////////////////////////////////////////////////////////


int main(void)  
{
	wdt_disable();
	IO_INIT();
	Uart_Init();
	LCD_ON();	                   //初始化 LCD1602 并显示制作者信息
	delay_nms(1500);
	DisplayListChar(0, 0, uctech); //输出英文 "Input Frequence:" 到LCD1602 第一行
	
	DisplayListChar(0, 5, Init);    //显示稍等
	
	CLR_DOOR;                       //关闭阀门
	_delay_loop_2(5);
	SET_CLEAR;
	_delay_loop_2(5);               //清空74ls393数据
	CLR_CLEAR;
	
	TCNT1H=0;
	TCNT1L=0;                        //清空T1计数器
	
	ASSR=_BV(AS2);                          //允许异步时钟
	TCCR2=_BV(CS22)|_BV(CS20);        
	TCCR1B=_BV(CS12)|_BV(CS11);            //外部T1引脚输入 下降沿有效 (一定要下降沿)
	TIMSK=_BV(TOIE1)|_BV(TOIE2);           //允许溢出中断
	
	sei();	
	
	while(1);	
}



/*----------------------系统初始化函数实体------------------*/

void IO_INIT(void)
{
	DDRB|=0x0f;
	PORTB&=0x0f;
	DDRC|=0x00;
	PORTC&=0x00;
	DDRD|=0xdc;
	PORTD&=0xdc;
}	

/*----------------------系统中断函数实体-----------------*/

ISR(TIMER1_OVF_vect)  //定时器1溢出中断  
{
	T1_OV_Times++;
}


ISR(TIMER2_OVF_vect)  //定时器2溢出中断  
{	
	if(T2_OV_Time==2)
		{
			CLR_DOOR;

			Timer1_Counter_L=TCNT1L;   //读取TCNT1数据要按照顺序,先低8位后高8位
			Timer1_Counter_H=TCNT1H;
		
			Frequence=((unsigned long)Timer1_Counter_H<<16)|((unsigned long)Timer1_Counter_L<<8)|((PINC&0x3c)>>2)|((PINC&0x03)<<6)|(PINB&0x30);
			
			if(T1_OV_Times!=0)        //其实这个是多余的,这里目的是测量16.7M 以上的频率 不过我们测量的频率不可能达到这个
				{
					Frequence+=(unsigned long)0xffff*0xff*T1_OV_Times;
					T1_OV_Times=0;
				}
			
			//printf("\n\nTCNT1H: 0X%X  TCNT1L: 0X%x",Timer1_Counter_H,Timer1_Counter_L);
			//printf("\nOverFlowTimes %d",T1_OV_Times);
			
			LongConvertToChar(Frequence);   //把Frequence 转换后的数据 放到 net[]数组里面
			DisplayListChar(0, 5, net);     //把net[]的数据输出到LCD
		
			SET_CLEAR;                  //一定要先把 74ls393 清零 再对TCNT1 清零
			_delay_loop_2(2);           //适当延时,其实可不要
			CLR_CLEAR;
			_delay_loop_2(2);
			
			TCNT1H=0x00;
			TCNT1L=0x00;			

			T2_OV_Time=1;             //启动下一次测量
		}
	else
		{	
			SET_DOOR;		
			T2_OV_Time=2;		      	
		}
}



/*----------------------LCD_1602函数实体------------------*/

void LCD_ON(void)
{
 delay_nms(400); //启动等待,等LCD讲入工作状态
 LCDInit(); //LCD初始化
 delay_nms(100); //延时片刻(可不要)
 DisplayListChar(0, 0, Owner);
 DisplayListChar(0, 5, net);
}

void UsePrintfToConvert(unsigned long WD)   //利用 printf 的转换功能 爽! ^.^
{
	SetPrintfConvertMode=1;  //设置 printf 为自定义转换模式
	printf("%13ld Hz",WD);    //net[]数组总共有 16 个成员 与LCD1602的一行16个位对应
	SetPrintfConvertMode=0;   //还原 printf 为 Uart 输出模式
	
	/*---------为输出数据添加逗号  999,999,999 ------------*/
	
	
    net[2]=net[4];
	net[3]=net[5];
	net[4]=net[6];
	if(net[2]!=' '||net[3]!=' '||net[4]!=' ')
	{
		if(net[4]!='-')
			{
				net[5]=',';
			}
	}
	net[6]=net[7];
	net[7]=net[8];
	net[8]=net[9];
	if(net[6]!=' '||net[7]!=' '||net[8]!=' ')
	{
		if(net[8]!='-')
			{
			net[9]=',';
			}
	}
}

void LongConvertToChar(unsigned long WD)
{
	UsePrintfToConvert(WD);
}

void WriteDataTo595(unsigned char WDLCD) // 74hc595 串行转并行输出
{
	unsigned char i;
	CLR_74LS595_CLK;
	for(i=0;i<8;i++)
		{
			CLR_74LS595_SHIFT;
			if(WDLCD&0x01)
				{
					SET_74LS595_DI;
				}
			else
				{
					CLR_74LS595_DI;
				}
			WDLCD>>=1;
			SET_74LS595_SHIFT;
		}
	_delay_loop_2(1);
	SET_74LS595_CLK;	
}

//写数据
void WriteDataLCD(unsigned char WDLCD)
{
 delay_nms(1);//适当加延时,避免 LCD1602 繁忙
 WriteDataTo595(WDLCD);
 SET_LCD_RS;
 CLR_LCD_RW;
 CLR_LCD_E; //若晶振速度太高可以在这后加小的延时
 _delay_loop_2(1);
 SET_LCD_E;
}

//写指令
void WriteCommandLCD(unsigned char WCLCD)
{
 delay_nms(1);//适当加延时,避免 LCD1602 繁忙
 WriteDataTo595(WCLCD);
 CLR_LCD_RS;
 CLR_LCD_RW; 
 CLR_LCD_E;
 _delay_loop_2(1);
 SET_LCD_E; 
}


void LCDInit(void) //LCM初始化
{
 WriteDataTo595(0);
 WriteCommandLCD(0x38); //三次显示模式设置,不检测忙信号
 delay_nms(15);
 WriteCommandLCD(0x38);
 delay_nms(5);
 WriteCommandLCD(0x38);
 delay_nms(5);
 
 WriteCommandLCD(0x38); //显示模式设置,开始要求每次检测忙信号
 WriteCommandLCD(0x08); //关闭显示
 WriteCommandLCD(0x01); //显示清屏
 WriteCommandLCD(0x06); // 显示光标移动设置
 WriteCommandLCD(0x0C); // 显示开及光标设置
}

//按指定位置显示一个字符
void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData)
{
 Y &= 0x1;
 X &= 0xF; //限制X不能大于15,Y不能大于1
 if (Y) X |= 0x40; //当要显示第二行时地址码+0x40;
 X |= 0x80; // 算出指令码
 WriteCommandLCD(X); //这里不检测忙信号,发送地址码
 WriteDataLCD(DData);
}

//按指定位置显示一串字符
void DisplayListChar(unsigned char X, unsigned char Y, unsigned char  *DData)
{
 unsigned char ListLength;

  ListLength = 0;
 Y &= 0x1;
 X &= 0xF; //限制X不能大于15,Y不能大于1
 while (DData[ListLength]>=0x20) //若到达字串尾则退出
  {
   if (X <= 0xF) //X坐标应小于0xF
    {
     DisplayOneChar(X, Y, DData[ListLength]); //显示单个字符
     ListLength++;
     X++;
    }
  }
}

/*----------------------串口函数实体------------------*/


void Uart_Init(void)
{
  UCSRB=_BV(RXEN)|_BV(TXEN); 
  UBRRL=51;   
  stdout=&mystd;
  stdin=&mystd;
}

int System_putchar(char c, FILE *stream)
{
	if(SetPrintfConvertMode==1)
	{
		net[Net_Pointer]=c;
		Net_Pointer++;
		if(Net_Pointer>=16)
		{
			Net_Pointer=0;
		}
		
	}
	else
	{
		if (c == '\n')
		System_putchar('\r', stream);
		loop_until_bit_is_set(UCSRA, UDRE);
		UDR = c;
	}
	
	return 0;
}


int System_getchar( FILE *stream)
{
	loop_until_bit_is_set(UCSRA,RXC);
	return UDR;
}

 

⌨️ 快捷键说明

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