51/AVR单片机技术驿站!  <在线翻译>     便利工具    特色网址   无弹窗、无插件的绿色站点...  英才招聘   学历查询  喜欢>>收藏我站 

当前位置:首页 > 单片机技术文章 > AVR单片机 > 详细内容
ATMEGA8单片机频率计程序与电路图
发布时间:2009/8/6  阅读次数:6694  字体大小: 【】 【】【

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

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

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

PCB原理图

/////////////////////////////以下为程序, 只有一个文件 main.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[] de指针

unsigned char Timer1_Counter_H=0;
unsigned char Timer1_Counter_L=0;
unsigned long Frequence=0;
unsigned char T2_OV_Time=1; //T2溢出对应de时间
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)               //其实这个shi多余de,这里目deshi测量16.7M 以上de频率 不过我们测量de频率不可能达到这个
         {
           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 转换后de数据 放到 net[]数组里面
       DisplayListChar(0, 5, net);         //把net[]de数据输出到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 de转换功能 爽! ^.^
{
SetPrintfConvertMode=1; //设置 printf 为自定义转换模式
printf("%13ld Hz",WD);       //net[]数组总共有 16 个成员 与LCD1602de一行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; //若晶振速度太高可以在这后加小de延时
_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;
}

我要评论
  • 匿名发表
  • [添加到收藏夹]
  • 发表评论:(匿名发表无需登录,已登录用户可直接发表。) 登录状态:未登录
最新评论
所有评论[0]
    暂无已审核评论!

网站导航 管理登陆 ┊ 免责声明 问题反馈  友链说明
本站部分内容来自网络共享资源,如有冒犯您的权利请来信告之删除或纠正!
不得对本站进行复制、盗链或镜像,转载内容须获得同意或授权;欢迎友情链接、站务合作!

    我要报警 Alexa
 mcusy_cn#126.com (请把#改成@) 交流:522422171
本站学习交流群:138..158(高级群1-)、77930286(高级群2)、61804809(群3)
Copyright© MCUSY All Rights Reserved
本站网警备案号: WZ36040002485
  ICP备案证书号:粤ICP备09034963号