|
基于AT89C51单片机设计了一款测量范围在10HZ-10KHZ的频率计,主要由输入放大电路,整形电路、单片机AT89C51和显示电路等组成。被测信号(正弦波或方波)通过放大、整形电路转换成同频率的方波脉冲信号,采用单片机内部的定时/计数器T0进行计数。放大整形后的信号输入到AT89C51单片机T0中断口使用其计数模式对输入信号进行计数,再利用内部定时器T1进行定时。最后在软件的主函数部分通过一系列计算得出频率,输送至LCD液晶显示屏输出测量输入信号值。
方案:
系统以AT89C51为核心,设计了一款测试范围在10Hz ~ 10KHz 的频率计。该系统主要设计思想是信号予处理电路 、串行通信电路 、测量数据显示电路和系统软件所组成, 其中信号予处理电路包含待测信号放大、波形变换、波形整形和分频电路。信号予处理电路中的放大器实现对待测信号的放大 ,降低对待测信号的幅度要求;波形变换和波形整形电路实现把正弦波样的正负交替的信号波形变换成可被单片机接受的信号。
Altium Designer画的原理图和PCB图如下:(51hei附件中可下载工程文件)
单片机源程序如下:
- #include <reg52.h>
-
- #define LCD1602_DB P0 //数据信号
- #define u32 unsigned long int
- #define u16 unsigned int
- #define u8 unsigned char
- u32 fre;
- u8 add;
- u8 WeiShu;
- u16 count;
- u16 count1;
- sbit LCD1602_RS=P2^6; //片选信号
- sbit LCD1602_RW=P2^5; //读写信号
- sbit LCD1602_E=P2^7; //使能信号
- u8 character[15]; //在屏幕上显示的字符串
- u8 character_1[]={"frequency lx"}; //显示
- u8 hz[]={"Hz"};
- u8 khz[]={"KHz"};
- void InitLcd1602();
- void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);
- void timer_init(); //中断初始化函数
- void delay_1s() //延迟1s
- {
- unsigned int i,j;
- for(i = 0;i<100;i++)
- for(j = 0;j<1000;j++);
- }
- // 等待液晶准备好
- void LcdWaitReady()
- {
- u8 sta;
- LCD1602_DB = 0xFF;
- LCD1602_RS = 0;
- LCD1602_RW = 1;
- do
- {
- LCD1602_E = 1;
- sta = LCD1602_DB; //读取状态字
- LCD1602_E = 0;
- }while (sta & 0x80); //bit7 等于 1 表示液晶正忙,重复检测直到其等于 0 为止
- }
- //向 LCD1602 液晶写入一字节命令,cmd-待写入命令值
- void LcdWriteCmd(unsigned char cmd)
- {
- LcdWaitReady();
- LCD1602_RS = 0;
- LCD1602_RW = 0;
- LCD1602_DB = cmd;
- LCD1602_E = 1;
- LCD1602_E = 0;
- }
- // 向 LCD1602 液晶写入一字节数据,dat-待写入数据值
- void LcdWriteDat(unsigned char dat)
- {
- LcdWaitReady();
- LCD1602_RS = 1;
- LCD1602_RW = 0;
- LCD1602_DB = dat;
- LCD1602_E = 1;
- LCD1602_E = 0;
- }
- // 设置显示 RAM 起始地址,亦即光标位置,(x,y)-对应屏幕上的字符坐标
- void LcdSetCursor(unsigned char x, unsigned char y)
- {
- u8 addr;
- if (y == 0){ //由输入的屏幕坐标计算显示 RAM 的地址
- addr = 0x00 + x; //第一行字符地址从 0x00 起始
- }else{
- addr = 0x40 + x; //第二行字符地址从 0x40 起始
- }
- LcdWriteCmd(addr | 0x80); //设置 RAM 地址
- }
- //在液晶上显示字符串,(x,y)-对应屏幕上的起始坐标,str-字符串指针
- void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str)
- {
- LcdSetCursor(x, y); //设置起始地址
- while (*str != '\0')
- { //连续写入字符串数据,直到检测到结束符
- LcdWriteDat(*str++); //先取 str 指向的数据,然后 str 自加 1
- }
- }
- // 初始化 1602 液晶
- void InitLcd1602()
- {
- LcdWriteCmd(0x38); //16*2 显示,5*7 点阵,8 位数据接口
- LcdWriteCmd(0x0C); //显示器开,光标关闭
- LcdWriteCmd(0x06); //文字不动,地址自动+1
- LcdWriteCmd(0x01); //清屏
- }
- void number_dispose() //数据处理
- {
- //character[15]={'\0'};
- u8 i,j=1;
- u32 temp;
- u32 number_sign;
-
- if(fre<1000)
- {
- temp=fre*100;
- number_sign=fre*100;
- while(temp>0) //计算位数
- {
- temp/=10;
- j++;
- }
- WeiShu=j;
- for(i=0;i<j;i++) //依次取余
- {
- if(i==2)
- character[j-i-1]='.';
- else
- {
- character[j-i-1]=number_sign%10+0x30;
- number_sign/=10;
- }
- }
- }
- else
- {
- temp=fre;
- number_sign=fre;
- while(temp>0) //计算位数
- {
- temp/=10;
- j++;
- }
- WeiShu=j;
- for(i=0;i<j;i++) //依次取余
- {
- if(i==3)
- character[j-i-1]='.';
- else
- {
- character[j-i-1]=number_sign%10+0x30;
- number_sign/=10;
- }
- }
- }
- }
- void main()
- {
- timer_init(); //定时/计数器初始化
- while(1)
- {
- number_dispose(); //数据处理
- InitLcd1602();
- LcdShowStr(0, 0, character_1);
- LcdShowStr(0, 1, character);
- if(fre<1000)
- LcdShowStr(WeiShu+1, 1, hz);
- else
- LcdShowStr(WeiShu+1, 1, khz);
- delay_1s();
- }
- }
- //定时/计数器初始化
- void timer_init(void) //定时/计数器初始化
- {
- TMOD=0x66; //计数器0和计数器1工作工作方式2,自动重装初值
- TH0=0; //计数器初值为0
- TL0=0;
- TR0=1; //计数器开始计数
- ET0=1; //打开计数器0中断
- TH1=0; //计数器初值为0
- TL1=0;
- TR1=1; //计数器开始计数
- ET1=1; //打开计数器1中断
- RCAP2H=(65536-62500)/256; //在程序初始化的时候给RCAP2L和RCAP2H赋值,
- RCAP2L=(65536-62500)%256; //TH2和TL2将会在中断产生时自动使TH2=RCAP2H,TL2=RCAP2L。
- TH2=RCAP2H; //12M晶振下每次中断62.5ms(1s=1000ms=62.5ms×16)
- TL2=RCAP2L;
- ET2=1; //打开定时器2中断
- TR2=1; //定时器2开始计时
- EA=1; //开总中断
- }
- //中断函数
- void timer2(void) interrupt 5 //定时器2中断(62.5ms)
- {
- add++;
- TF2=0; //定时器2的中断标志位TF2不能够由硬件清零,所以要在中断服务程序中将其清零
- if (add==32) //定时1s时间到
- {
- add=0; //计时清0
- EA=0; //关中断
- fre=(long)count1*256+TL1; //count*256强制转换成long型,否则将不产生进位~先判断分频后(计数器1)
- // FLAG = 0;
- if(fre<2000)//如果不到200KHz则读取分频前(计数器0)频率(200K÷100=2000)
- {
- fre = (long)count*256+TL0;
- // FLAG = 1;
- }
- // if(!FLAG)
- // {
- // fre = fre *100;//100分频
- // }
- TL0=0; //清零计数器0计数
- TH0=0;
- TL1=0;
- TH1=0;
- count=0; //清零计数器0计数
- count1=0;
- EA=1; //开中断
- }
- }
- void timer0(void) interrupt 1 //计数器0中断
- {
- count++;
- }
复制代码
所有资料51hei提供下载:
|
评分
-
查看全部评分
|