您当前的位置:五五电子网电子知识单片机-工控设备AVR单片机Atmega8单片机频率计C程序 正文
Atmega8单片机频率计C程序

Atmega8单片机频率计C程序

点击数:7630 次   录入时间:03-04 11:52:58   整理:http://www.55dianzi.com   AVR单片机

实验目标
        频率计是我们经常会用到的实验仪器之一,本实验要使用 单片机 和计数电路及液晶器件来设计一个宽频的频率计。
期望达到10Hz-1.1G范围的频率精确测量。
实验电路图(初步方案)
1) 计数及显示电路:

点击看大图
 
2)前置放大及分频电路:
设计设计测量频率的思路

        频率的测量实际上就是在1S时间内对信号进行计数,计数值就是信号频率。用 单片机 设计频率计通常采用两种办法,1)使用单片机自带的计数器对输入脉冲进行计数,或者测量信号的周期;2)单片机外部使用计数器对脉冲信号进行计数,计数值再由单片机读取。

        由于 单片机 自带计数器输入时钟的频率通常只能是系统时钟频率的几分之一甚至几十分之一,因此采用单片机的计数器直接测量信号频率就受到了很大的限制。

        本实验电路采用方式2,使用一片 74LS393四位双二进制计数器和Atmega8的T1计数器组成了24位计数器,最大计数值为16777215。如果输入信号经过MB501分频器进行64分频后再进行测量,则固定1S时基下最高测量频率为1073.741760Mhz。

        为了方便得到准确的1秒钟测量闸门信号,我们使用了Atmega8的异步实时时钟功能,采用32.768Khz的晶振由TC2产生1秒钟的定时信号。

测量频率原理:
 
        单片机 打开测量闸门,即PB1输出高电平,同时TC2定时器启动。74LS393开始对输入脉冲进行计数,74LS393每计数达256时,Atmega8的T1计数器也向上计数1次。当1S 定时到达时,单片机产生中断,PB1输出低电平关闭测量闸门,然后Atmega8读取74LS393和T1的计数值,然后送LCD显示。
 
        由于1S的测量闸门时间在业余条件下不好测试,因此,实验程序中在LCD上同时显示实时时钟用于判断1S闸门时间的准确性。实验中,我使用CDMA手机上显示的GPS卫星精确时间进行比较。手机时间显示的最小单位是分钟,测量时一旦手机分钟值发生跳变,则立即记录下LCD显示的秒值,这样的话让频率计运行一段时间后,再多次记录下LCD显示的秒,就可以准确判断频率计的异步时钟是否准确。实验过程中,我让频率计走了10个小数左右,测量的1S时钟还是非常准确的。

频率测量源代码:
#include
#include
#include "lcd.h"
#include "bmp.h"

unsigned long counter;
unsigned char countlow;
unsigned char fre[]="00.000000";
unsigned char time[]="00:00:00";

#pragma interrupt_handler timer2_ovf_isr:iv_TIMER2_OVF
void timer2_ovf_isr(void)
{
unsigned char i;
//TCCR2=0;

PORTB &= ~0X02; //关闭闸门

//读取计数值
counter = TCNT1; //读取T/C1计数值(频率值的高16位)
counter = counter*256; //计算频率值的高16位
countlow = (PIND & 0b11000000)|(PINC & 0b00111111);
//读取计数值的低8位
counter = counter + countlow; //计算频率值

PORTD |= 0X01; //74LS393清零
TCNT1 = 0;

PORTD &= ~0X01; //关闭清零
TCNT2 = 0X80; //定时时间1秒

PORTB |= 0X02; //打开闸门

//实时时钟显示
time[7]++;

fre[0]=counter /10000000+0x30;
counter=counter %10000000;
fre[1]=counter /1000000+0x30;
counter=counter %1000000;
fre[3]=counter /100000+0x30;
counter=counter %100000;
fre[4]=counter /10000+0x30;

counter=counter %10000;
fre[5]=counter /1000+0x30;
counter=counter %1000;
fre[6]=counter /100+0x30;
counter=counter %100;
fre[7]=counter /10 + 0x30;
fre[8]=counter %10 + 0x30;

LCD_write_String(0,2,fre);
LCD_draw_map(14,2,Bmp003,7,14); //显示小数点
LCD_draw_map(62,2,MHz,22,14); //显示频率单位

if ( time[7] > (9+0x30) )
{
time[6] ++;
time[7] -= 10;
}
if ( time[6] > (5+0x30) )
{
time[4] ++;
time[6] -= 6;
}
if (time[4]> (9+0x30))
{
time[3]++;
time[4]-=10;
}
if (time[3] > (5+0x30))
{
time[1]++;
time[3]-=6;
}
if (time[1]>(9+0x30))
{
time[0]++;
time[1]-=10;
}
LCD_write_String(2,4,time);
LCD_draw_map(16,4,Bmp002,7,14); //显示“:”字符
LCD_draw_map(37,4,Bmp002,7,14);

}

/******************************************************************************/
void main(void)
{
unsigned char i;
OSCCAL=0xA3; // 8M系统内部时钟校准

//设置MCU的I/O口
DDRB |= LCD_RST | LCD_DC | LCD_CE | SPI_MOSI | SPI_CLK ;

DDRB |= 0x02; //计数闸门
DDRD |= 0X01; //74LS393清零
//DDRD |= 0X08; //LED
//DDRD &= ~0X20;
DDRC &= 0B11000000;
DDRD &= 0B00111111;

SPSR |= BIT(SPI2X); // 设置SPI时钟倍速
SPCR |= BIT(SPE)|BIT(MSTR); // 使能SPI接口,主机模式,4M时钟

LCD_init();
//LCD_clear(); // 清屏
LCD_draw_map(12,0,Bmp001,60,13);

ASSR = 1 <TCNT2 = 0X80; //定时时间1秒
TCCR2 = (1<TIMSK |= BIT(TOIE2); //允许TC2溢出中断

TCCR1B |= BIT(CS12)|BIT(CS11)|BIT(CS10); //时钟外部T1输入,上升源驱动

SEI();

while(1)
{

}
}

3310液晶显示源代码:


#include  #include  #include "lcd.h" #include "6x8.h" #include "chinese.h" /*---------- LCD_init : 3310LCD初始化 编写日期 :2004-8-10 最后修改日期 :2004-8-10 ------------*/ void LCD_init(void) { PORTB &= ~LCD_RST; // 产生一个让LCD复位的低电平脉冲 delay_1us(); PORTB |= LCD_RST; PORTB &= ~LCD_CE ; // 关闭LCD delay_1us(); PORTB |= LCD_CE; // 使能LCD delay_1us(); LCD_write_byte(0x21, 0); // 使用扩展命令设置LCD模式 LCD_write_byte(0xc8, 0); // 设置偏置电压 LCD_write_byte(0x06, 0); // 温度校正 LCD_write_byte(0x13, 0); // 1:48 LCD_write_byte(0x20, 0); // 使用基本命令 LCD_clear(); // 清屏 LCD_write_byte(0x0c, 0); // 设定显示模式,正常显示 PORTB &= ~LCD_CE ; // 关闭LCD //LCD_clear(); } /*-------- LCD_clear : LCD清屏函数 编写日期 :2004-8-10 最后修改日期 :2004-8-10 -------------*/ void LCD_clear(void) { unsigned int i; LCD_write_byte(0x0c, 0); LCD_write_byte(0x80, 0); for (i=0; i<504; i++) LCD_write_byte(0, 1); } /*--------- LCD_set_XY : 设置LCD坐标函数 输入参数:X :0-83 Y :0-5 编写日期 :2004-8-10 最后修改日期 :2004-8-10 -----------*/ void LCD_set_XY(unsigned char X, unsigned char Y) { LCD_write_byte(0x40 | Y, 0); // column LCD_write_byte(0x80 | X, 0); // row } /*----------- LCD_write_char : 显示英文字符 输入参数:c :显示的字符; 编写日期 :2004-8-10 最后修改日期 :2004-8-10 -------------------*/ void LCD_write_char(unsigned char c) { unsigned char line; //c -= 32; //for (line=0; line<6; line++) //LCD_write_byte(font6x8[c][line], 1); for (line=0; line<7; line++) LCD_write_byte(font7x13[c][line], 1); for (line=7; line<14; line++) LCD_write_byte(font7x13[c][line], 1); } /*---------- LCD_write_char : 英文字符串显示函数 输入参数:*s :英文字符串指针; X、Y : 显示字符串的位置 编写日期 :2004-8-10 最后修改日期 :2004-8-10 ------------*/ void LCD_write_String(unsigned char X,unsigned char Y,char *s) { unsigned char line; unsigned char i="0"; while (*s) { LCD_set_XY(X+i*7,Y); for (line=0; line<7; line++) LCD_write_byte(font7x13[*s-0X30][line], 1); LCD_set_XY(X+i*7,Y+1); for (line=7; line<14; line++) LCD_write_byte(font7x13[*s-0X30][line], 1); s++; i++; } } /*-------------------- LCD_write_chi: 在LCD上显示汉字 输入参数:X、Y :显示汉字的起始X、Y坐标; ch_with :汉字点阵的宽度 num :显示汉字的个数; line :汉字点阵数组中的起始行数 row :汉字显示的行间距 编写日期 :2004-8-11 最后修改日期 :2004-8-12 ---------------------------*/ void LCD_write_chi(unsigned char X, unsigned char Y, unsigned char ch_with,unsigned char num, unsigned char line,unsigned char row) { unsigned char i,n; LCD_set_XY(X,Y); //设置初始位置 for (i=0;i{ for (n=0; n{ if (n==ch_with) //写汉字的下半部分 { if (i==0) LCD_set_XY(X,Y+1); else LCD_set_XY((X+(ch_with+row)*i),Y+1); } LCD_write_byte(china_char[line+i][n],1); } i++; LCD_set_XY((X+(ch_with+row)*i),Y); } } /*-------------------------- LCD_write_chi: 汉字移动 输入参数:X、Y :显示汉字的起始X、Y坐标; T :移动速度; 编写日期 :2004-8-13 最后修改日期 :2004-8-13 -------------------------*/ void LCD_ MOV e_chi (unsigned char X, unsigned char Y, unsigned char T) { unsigned char i,n,j=0; unsigned char buffer_h[84]={0}; unsigned char buffer_l[84]={0}; for (i=0; i<156; i++) { buffer_h[83] = china_char[i/12][j]; buffer_l[83] = china_char[i/12][j+12]; j++; if (j==12) j="0"; for (n=0; n<83; n++) { buffer_h[n]=buffer_h[n+1]; buffer_l[n]=buffer_l[n+1]; } LCD_set_XY(X,Y); for (n=0; n<83; n++) { LCD_write_byte(buffer_h[n],1); } LCD_set_XY(X,Y+1); for (n=0; n<83; n++) { LCD_write_byte(buffer_l[n],1); } delay_nms(T); } } /*------------ LCD_draw_map : 位图绘制函数 输入参数:X、Y :位图绘制的起始X、Y坐标; *map :位图点阵数据; Pix_x :位图像素(长) Pix_y :位图像素(宽) 编写日期 :2004-8-13 最后修改日期 :2004-8-13 --------------------*/ void LCD_draw_map(unsigned char X,unsigned char Y,unsigned char *map, unsigned char Pix_x,unsigned char Pix_y) { unsigned int i,n; unsigned char row; if (Pix_y%8==0) row="Pix"_y/8; //计算位图所占行数 else row=Pix_y/8+1; for (n=0;n{ LCD_set_XY(X,Y); for(i=0; i{ LCD_write_byte(map[i+n*Pix_x], 1); } Y++; //换行 } } /*------------------------ LCD_write_byte : 使用SPI接口写数据到LCD 输入参数:data :写入的数据; command :写数据/命令选择; 编写日期 :2004-8-10 最后修改日期 :2004-8-13 --------------------------------------*/ void LCD_write_byte(unsigned char data, unsigned char command) { PORTB &= ~LCD_CE ; // 使能LCD if (command == 0) PORTB &= ~LCD_DC ; // 传送命令 else PORTB |= LCD_DC ; // 传送数据 SPDR = data; // 传送数据到SPI寄存器 while ((SPSR & 0x80) == 0); // 等待数据传送完毕 PORTB |= LCD_CE ; // 关闭LCD }

[1] [2]  下一页


本文关键字:单片机  程序  AVR单片机单片机-工控设备 - AVR单片机