实验具体内容
在 Proteus 环境下搭建如下图所示的电路图:

控制要求:
本实验利用 LCD1602 和 AD0808 实现简单的交流信号过零检测与频率分析。要求信号幅度变化时(满量程的 5%-95%) ,不影响检测的结果。频率检测的结果通过 LCD1602 的第一行显示出来,信号过零时,能够通过 P2.6 输出一个脉冲宽度为 5us 的脉冲信号。
编程思路
LCD1602 的控制方法按 3.7 节所示方法进行 ADC0808 的控制方法按 3.8.1 所示方法进行。这里主要是过零点的检测方法如何实现。不能采用判断所采集到的数据是否为 0 的方法来实现,因为你的采集时刻不一定能够严格对准过零时刻。但是,我们注意到在 0 点的两边信号的极性是发生变化的,我们可以利用这一特点来实现过零检测。正弦波每个周期有两个过零点,因此,1s 内过零次数除以 2 就是信号的频率。因此,在程序中可以这样实现 。当每次采集到一个新的数据之后都要看一下这个数据是正数还是负数。当这个数大于 128 时是正数,当它小于 128 时是负数。判断当前数据的正负极性和上一个数据的正负极性是否一致,如果不一致,则说明经过了一次过零点,将其记录入次数计数器。
ADC0808 的 CLK 仍然用定时器 T1 来实现,可以将其设置为 50kHz(硬件实现时可以更高,软件仿真再高将难以实现)。利用定时器 T0 实现 50ms 定时,并配合软件实现 1s 钟定时。采用 12M 晶振时,T0 采用方式 1,则处置应为(TH0=0x3C,TL0=0xB0)。
但是,由于中断处理函数需要一定的响应时间,因此这个参数只是理论计算结果,要根据实测情况稍作调整。同样 T1 理论计算值和实际输出值可能也会有一定的差距,也要进行调整。
流程图

实验过程
① 根据上述实验内容,参考 1.2.2,在 Proteus 环境下建立图3.22 所示原理图,并将其保存为 ADC0808_self.DSN 文件。
② 根据控制要求和编程思路画出流程图,并编写源程序,将其保存为 ADC0808_self.c。
③ 运行 Keil uVision2 开发环境,按照 1.1.3 节介绍的方法建立工程ADC0808_self.uV2,CPU 为 AT89C51,包含启动文件STARTUP.A51。
④ 按照 1.2.2 第(6)节介绍的方法将 C 语言源程序ADC0808_self.c 加入工程ADC0808_self.uV2,并设置工程ADC0808_self.uV2 属性,将其晶振频率设置为12MHz,选择输出可执行文件,仿真方式为选择硬仿真,并选择其中的“PROTEUS VSM MONITOR 51 DRIVER”仿真器。
⑤ 构造(Build)工程 ADC0808_self.uV2。如果输入有误进行修改,直至构造正确,生成可执行程序 ADC0808_self.hex 为止。
⑥ 为 AT89C51 设置可执行程序 ADC0808_self.hex。
⑦ 运行程序,观察计算结果,并验证其是否正确。
⑧ 改变 RV1 的抽头位置,从而改变输入信号的幅值,观察计算结果是否正确。
⑨ 更改信号发射器的频率,再次验证其功能是否正确。(注意:因为是软仿真,所以信号采集的速度受到限制,因此所输入的交流信号频率也不能太高,可以在 200Hz以内尝试)。
实验截图:
5%幅值:

95%幅值:

150Hz,幅值5V信号频率采集:

实验源程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
| #include <reg51.h> #include <intrins.h> #include <stdio.h> #include <string.h> #define uint unsigned int #define uchar unsigned char uchar data line_data[16]; sbit LCD_RS=P2^0; sbit LCD_RW=P2^1; sbit LCD_EN=P2^2; sbit CLK=P2^3; sbit Start=P2^4; sbit OE=P2^5; sbit Out_pulse=P2^6; sbit EOC = P2^7; uint Hz_count; uchar n,count0,data_old,data_new; bit Hz_sum; void delay_ms(uint xms) { uint i,j; for(i=xms;i>0;i--) for(j=110;j>0;j--); }
bit lcd_busy() { bit flag; LCD_RS = 0; LCD_RW = 1; LCD_EN = 1; _nop_(); _nop_(); _nop_(); _nop_(); flag = (bit)(P1&0x80); LCD_EN = 0; return flag; } void s_timer1() interrupt 3 { CLK=~CLK; }
void s_timer0() interrupt 1 { TH0=0x3C; TL0=0x0B0; count0++; if(count0==20) { Hz_sum = 1; count0=0; } }
void lcd_wcmd(uchar cmd) { while(lcd_busy()); LCD_RS=0; LCD_RW=0; LCD_EN=0; _nop_(); _nop_(); P1=cmd; _nop_(); _nop_(); _nop_(); _nop_(); LCD_EN=1; _nop_(); _nop_(); _nop_(); _nop_(); LCD_EN=0; } void lcd_clr() { lcd_wcmd(0x01); delay_ms(2); } void lcd_wdat(uchar dat) { while(lcd_busy()); LCD_RS=1; LCD_RW=0; LCD_EN=0; _nop_(); _nop_(); P1=dat; _nop_(); _nop_(); _nop_(); _nop_(); LCD_EN=1; _nop_(); _nop_(); _nop_(); _nop_(); LCD_EN=0; } void lcd_init() { delay_ms(15); lcd_wcmd(0x30); delay_ms(5); lcd_wcmd(0x0c); delay_ms(5); lcd_wcmd(0x06); delay_ms(5); lcd_wcmd(0x01); delay_ms(5); } void sysinit() { Hz_count = 0; CLK = 0; OE = 0; TMOD=0x21; TH1=0xF6; TL1=0xF6; TH0=0x3C; TL0=0x0B0; EA=1; ET1=1; TR1=1; ET0=1; TR0=1; } uchar sample() { uchar temp; Start = 1; Start = 0; while(EOC==0); P0 = 0xff; OE = 1; temp = P0; OE = 0; return(temp); } void main() { uchar i,Hz_result[6]; delay_ms(10); lcd_init(); sysinit(); while(1) { data_new = sample(); if(((data_new>128)&&(data_old<128))((data_new<128)&&(data_old>128))) { Hz_count++; Out_pulse=1; _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); Out_pulse=0; data_old = data_new; }
if(Hz_sum==1) { lcd_clr(); Hz_count = Hz_count/2; memset(line_data,0,16); n = 0; lcd_wcmd(0x000x80); line_data[n++]='f'; line_data[n++]=':'; sprintf(Hz_result,"%d",Hz_count); strcat(line_data,Hz_result); while(line_data[++n]!='\0'); line_data[n++]='H'; line_data[n++]='z'; line_data[n]='\0'; i=0; while(line_data[i]!='\0') { lcd_wdat(line_data[i]); i++; } Hz_sum = 0; Hz_count = 0; } } }
|