ATMEGA8单片机频率计程序与电路图

发布者:和谐共处最新更新时间:2017-12-17 来源: eefocus关键字:ATMEGA8  单片机  频率计 手机看文章 扫描二维码
随时随地手机看文章

原理上采用32.768K外部晶振产生异步时钟信号 ,作为M8定时器2的时钟源,设定1024的预分频,可以得到TCNT2溢出的精确时间为1s,在溢出中断时控制74ls00与非门进而控制被测信号的通断,累计1s 内计数器获得的值,经过简单的运算则可获得被测信号的频率 

M8 采用内部 8M 内部RC震荡 工作模式 , 电路采用74ls393 对被测信号进行预分频,相当于扩张T1计数器的位数,T1 为16位,74ls393为8位,扩展后为24位,T1不溢出的话 最高可测 16.777216M ,溢出则累计中断次数然后进行累加即可。(另外添加74ls393进行预分频的目的是为了解决T1引脚时钟信号不宜大于 单片机 工作频率的二分之一的问题) 


目前测频 4M 已经成功通过,由于没有函数信号发生器,所以其他高频还没有做测试 


/////////////////////////////以下为程序, 只有一个文件 main.c ///////////////////////////////// 

#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  

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

#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   _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; 


关键字:ATMEGA8  单片机  频率计 引用地址:ATMEGA8单片机频率计程序与电路图

上一篇:AT90S8515点阵C语言编程实例源程序
下一篇:AVR模拟比较器范例

推荐阅读最新更新时间:2024-03-16 15:49

基于单片机+CPLD的多路精确延时控制系统设计
1 引言 现代控制系统中控制对象可能是复杂、分散的,而且往往是并行、独立工作的,但整体上它们是相互关联的有机组合。因此,控制信号的时序逻辑则要求更加精确。 CPLD单片机为控制系统提供了技术支持,由CPLD和单片机组成的多机系统具有逻辑控制方便,时序精确,并行工作,人机接口友好等优点。因此,本文提出了一种基于CPLD与单片机控制的多路精确延时控制系统的设计方案。 2 设计指标与系统原理 2.1 设计指标 输出多路脉宽为10 ms正脉冲信号; 脉冲输出时间独立调节、显示; 时间调整范围与精度为微秒级的调整范围为l~199μs,调节精度为lμs;毫秒级的调整范围为1~199 ms,调整精度为1 ms; 提供计时基准信号和
[单片机]
基于<font color='red'>单片机</font>+CPLD的多路精确延时控制系统设计
STM32单片机(12) 红外信号接收解码(外部中断)
本程序主要利用外部中断,实现红外遥控器信号接收解码,并利用串口通信把编码传至计算机显示 注:请用质量好点的遥控器实验,用了劣质遥控器浪费了一天时间,数据位接收总是不完整,后来用宿舍空调遥控器就解码成功了 相关资料 STM32单片机学习(2) 外部中断 http://blog.csdn.net/leytton/article/details/38063335 STM32单片机学习(3) 串口中断通信 http://blog.csdn.net/leytton/article/details/38393553 STM32单片机学习(7) 串口通信printf重定向 http://blog.csdn.net/leytton/ar
[单片机]
51单片机解决调试过程
对于一个新设计的电路板,调试起来往往会遇到一些困难,特别是当板比较大、元件比较多时,往往无从下手。但如果掌握好一套合理的调试方法,调试起来将会事半功倍。对于刚拿回来的新PCB板,我们首先要大概观察一下,板上是否存在问题,例如是否有明显的裂痕,有无短路、开路等现象。如果有必要的话,可以检查一下电源跟地线之间的电阻是否足够大。 然后就是安装元件了。相互独立的模块,如果您没有把握保证它们工作正常时,最好不要全部都装上,而是一部分一部分的装上(对于比较小的电路,可以一次全部装上),这样容易确定故障范围,免得到时遇到问题时,无从下手。一般来说,可以把电源部分先装好,然后就上电检测电源输出电压是否正常。如果在上电时您没有太大的把握(即使有
[单片机]
基于FPGA/MCU结构的线性调频高度表设计
   1 引言      无线电高度表不仅可以精确测量飞行器与地面或海面的相对高度,而且还可以测量地表 粗糙度、海洋波浪高度等多种参数,在飞机的自动着陆、自动导航、地形匹配等领域得到了 广泛的应用。无线电高度表主要分为调频连续波体制和脉冲体制两种,调频连续波体制适合 1500m 以内的低高度应用,脉冲体制适合1500m 以上的中高高度应用。本文介绍了一种基于 FPGA/MCU 结构的线性调频(LFMCW)连续波高度表,具有精度高,结构简单,可靠性高,成 本低等特点。       2 工作原理      线性调频连续波高度表的基本原理为 :采用三角波线性调频微波振荡源,经发射天线 辐射等幅调频波,经过与飞行器飞行高度成正比例的时间延
[嵌入式]
基于FPGA/<font color='red'>MCU</font>结构的线性调频高度表设计
SAM4E单片机之旅——13、LCD之ASF初步
在Atmel Studio 6中,集成了Atmel Software Framework(ASF框架)。通过它提供的库,可以很快速地完成新的项目。 这次的最终目标使用ASF在LCD上显示出文字“Hello World!”,现阶段目标是点亮LCD的背光,学习目标是了解怎么样使用ASF提供的模块。 一、 ASF Wizard 新建一个项目,根据所使用的开发板选择模板。 然后可以通过ASF Wizard进行所需模块的配置。 默认情况下,已经选择了两个模块。在之前我们以前使用过了其中Generic board support模块提供的头文件sam4e_ek.h了。 为了解模块添加的方法,先把这两个模块移除。 二、
[单片机]
SAM4E<font color='red'>单片机</font>之旅——13、LCD之ASF初步
信号链MCU第一股!芯海科技科创板IPO过会
7月17日,上海证券交易所科创板股票上市委员会召开了2020年第54次审议会议,根据审议结果显示,芯海科技科创板IPO成功过会。 据招股书显示,芯海科技成立于2003年9月,一直专注于高精度ADC芯片的设计和研发,早在2007年,芯海科技就推出了24位高精度ADC芯片CS1242,有效位数为21位,性能指标达到TI公司的ADS1240同等水平。 在此之前,由于国内ADC芯片精度不够,准确度差,国内主要高端衡器厂商采购的主要是以TI公司芯片为代表的进口芯片(例如ADS1240),而CS1242的量产打破了中国中高端衡器芯片市场被外国垄断,完全依靠进口的格局,实现了国内中高端衡器国产芯片从无到有的替代过程。 2011年,芯海科技推
[手机便携]
信号链<font color='red'>MCU</font>第一股!芯海科技科创板IPO过会
C51简介及Keil的使用
前言 此文档主要是针对有一定C/C++编程基础,并打算用Keil从事C51开发的开发人员。C51涉及的知识比较多,但是入门基本的开发,还是容易的。 C51简介 1. C51概念 C51继承于C语言,主要运行于51内核的单片机平台。单片机,单片微型计算机器(SingleChipMicrocomputer)的简称,又称微控制单元(MicroControllerUnit,MCU)。MCU由CPU、RAM、ROM、I/O、中断系统、晶振等组成。51内核的单片机都是8位的,因为数据I/O是8位的,但是地址总线是16位的。基于51内核的单片机有很多种,如8051、80515等。 存储器:包括片内存储器、片外存储器。片内存储器一般包括2
[单片机]
C51简介及Keil的使用
TI - MCU - MSP430使用指南12 -> GPIO
GPIO即通用输入输出接口,是MCU最基本的功能,可以控制I/O口的高低电平,输入输出或映射到其他模块等功能。 如下图所示,为MSP430FR2355芯片的引脚图: 在图中,每个引脚后标注的则是每个引脚具备的复用功能,GPIO是基本功能,除去电源,地,时钟等引脚,每个引脚都可作为通用IO口使用,那么如何按照自己的要求配置每个引脚的功能呢? 下面就描述下GPIO引脚相关的寄存器(MSP430FR2xx/FR4xx): 注:并非每个MSP430 MCU都包含下属所有的寄存器,根据MCU功能的复杂性决定,具体包含的寄存器名称和数量,请查看每个芯片的datasheet和user’s guide。 首先先整体看一下GP
[单片机]
TI - <font color='red'>MCU</font> - MSP430使用指南12 -> GPIO
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved