/**************************************************************** ** 功能: 1、测频、测周、测占空比(发挥部分) 2、显示:显示刷新时间1~10秒连续可调 3、能够自检 误差:≤ 1% 主要技术指标: 1、被测信号频率范围: a、1Hz~100kHz b、测量误差≤1%(基本要求) a、0.5Hz~2MHz(幅度0.1V~5V) b、误差为0.01%(发挥部分) 2、最大闸门时间≤10s,显示刷新时间1~10秒连续可调。 测量方法: 多周期同步测频法 ** *****************************************************************/ /*共阴数码管码表 0 ~ F uchar code table[] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71}; void timer2(void) interrupt 5 { /*定时器2必须由软件对溢出标志位进行清0,硬件无法实现对其清0,这一点与定时器0和1不同 TF2 = 0; //进入中断服务程序即对标志位清0 } */ #include #include #define uint unsigned int #define uchar unsigned char #define ulong unsigned long sbit rs = P1^0; sbit wr = P1^1; sbit en = P1^2; //sbit psb=P3^7;//串,并方式选择,学校的板子用跳帽选择,不需要软件设置 sbit P0_0 = P0^0; //D0 ~ D7位的位定义 sbit P0_1 = P0^1; sbit P0_2 = P0^2; sbit P0_3 = P0^3; sbit P0_4 = P0^4; sbit P0_5 = P0^5; sbit P0_6 = P0^6; sbit P0_7 = P0^7; sbit oe = P1^3; //位定义片选、段选、位选 sbit du = P1^4; sbit we = P1^5; sbit key_fre = P2^0; sbit key_cyc = P2^1; sbit key_jz = P2^3; sbit key_mk = P2^2; sbit P3_3 = P3^3; uint count_high; uint count_low; uchar code table[] = { //共阴数码管0 - 9码表 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f}; uchar code table2[] = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39}; uchar code table3[] = {"基频:"}; uchar code table4[] = {"基周:"}; uchar code table5[] = {"频率:"}; uchar code table6[] = {"周期:"}; uchar code table7[] = {"误差:"}; uchar code table8[] = {".%"}; uchar code table9[] = {"脉宽:"}; uchar code table10[] = {"占空比:"}; uchar flag = 0; //用来设定定时时间的标志 uchar flag2 = 0; //用来判断计数是否为超过65535的数 uchar flag3 = 0; ulong count1 = 0; //外来脉冲的计数值 ulong count0 = 0; uchar flag_sx = 0; uchar flag_func = 0; void delay(uint z); //延时函数声明 void disp(ulong z); void disp_cycle(ulong z); void disp2_cycle(ulong z); // void disp2(ulong z); void disp3(ulong x, ulong y); int swap(int x); //交换函数声明 void write_com(uint com); //写命令函数 void write_data(uint date); //写数据函数 void pos(uchar x,uchar y); //位置设定函数 void lcd_init(); //初始化函数 void t2_init(); void t0_init(); void write_date(float date); //写数据函数 void read_count(); void t0_t1_init(); void sw_1(void); void sw_2(void); void main() { en = 0; //打开片选 t0_t1_init(); /*while(1) { if(flag2) { count = count * 102; while(count == count) { disp(count); } } }*/ lcd_init(); t2_init(); while(1) { /*while(!key_fre) { disp(count); } while(!key_cyc) { disp_cycle(count); //检测是否周期键按下,是的话则进行周期测量与显示 } P0 = 0xff; we = 1; we = 0;*/ while(!key_mk) { delay(1); while(!key_mk) { write_com(0x01); //清屏 TMOD = 0X90; while(1) { TH1 = 0; TL1 = 0; while(P3_3 == 1); TR1 = 1; while(P3_3 == 0); while(P3_3 == 1); TR1 = 0; { read_count(); } if(!key_cyc || !key_fre) { //P2 = 0xff; //只要有其他键按下,D8灯灭 t0_t1_init(); t2_init(); break; } } } } while(!key_jz) { delay(1); while(!key_jz) { //init(); //write_com(0x01); //清屏 while(1) { disp3(count1, count0); if(!key_cyc || !key_fre || !key_mk) { P2 = 0xff; //只要有其他键按下,D8灯灭 break; } } } } while(!key_fre) { delay(1); while(!key_fre) { //init(); write_com(0x01); //清屏 while(1) { P2 = 0xfe; //频率键按下则D8亮灯 disp(count1); disp2(count0); //disp3(count1, count0); if(!key_cyc || !key_jz || !key_mk) { P2 = 0xff; //只要有其他键按下,D8灯灭 break; } } } } while(!key_cyc) { delay(1); while(!key_cyc) { //init(); write_com(0x01); //清屏 while(1) { P2 = 0xfd; //周期键按下则D9亮灯 disp_cycle(count1); disp2_cycle(count0); if(!key_fre || !key_jz || !key_mk) { P2 = 0xff; //只要有其他键按下,D9灯灭 break; } } } } } } void t1(void) interrupt 3 //被测频率T1口进 { if(flag < 20) //如果标志位小于20时就进入了定时器1中断,表明数值超过65535,则另行处理 { flag2=1; } } void t0(void) interrupt 1 //基准频率T0口进 { if(flag < 20) //如果标志位小于20时就进入了定时器1中断,表明数值超过65535,则另行处理 { flag3=1; } /*ET0 = 0; //禁止计数器0中断,后面再开,为了精准定时 flag++; //延时时间标志位 if(flag == 20) //如果时间到了1S,则进行数值处理 { flag = 0; //标志位清0 TR1 = 0; //关计数器 count = (TH1 * 256 + TL1) + flag2 * 65535; //读取数值 flag2 = 0; //计数标志位清0 TH1 = 0; //计数器1的值清0 TL1 = 0; TR1 = 1; //开计数器 } TH0 = (65535 - 50000) / 256; //定时器0送初值 TL0 = (65535 - 50000) % 256; TR0 = 1; //?貌似前面没关定时器嘛 ET0 = 1; //允许计数器0中断 */ } void t2(void) interrupt 5 //T2可用于精确定时,但不要用于按键检测 { TF2 = 0; ET2 = 0; //禁止计数器0中断,后面再开,为了精准定时 flag++; //延时时间标志位 if(flag == 20) //如果时间到了1S,则进行数值处理 { flag = 0; //标志位清0 TR1 = 0; TR0 = 0; //关计数器 count1 = (TH1 * 256 + TL1) + flag2 * 65535; //读取数值 被测频率 count0 = (TH0 * 256 + TL0) + flag3 * 65535; //基准频率 flag2 = 0; //计数标志位清0 flag3 = 0; TH1 = 0; //计数器1的值清0 TL1 = 0; TH0 = 0; TL0 = 0; TR1 = 1; //开计数器 TR0 = 1; } TR2 = 1; //?貌似前面没关定时器嘛 ET2 = 1; //允许计数器2中断 } void int0(void) interrupt 0 //中断扫描方式可提高按键扫描的工作效率 { } void t0_init() { TH0 = (65535 - 50000) / 256; //定时器0初值 TL0 = (65535 - 50000) % 256; EA = 1; //总中断使能 ET0 = 1; TR0 = 1; //打开定时器0 } void t2_init() { RCAP2H = (65535 - 50000) / 256; RCAP2L = (65535 - 50000) % 256; //C_T2 = 1; ET2 = 1; TR2 = 1; EA = 1; } void int0_init() { EX0 = 1; IT0 = 1; EA = 1; } //刷新及显示子程序 void disp_cycle(ulong z) // { ulong y = z; ulong x; uchar i; // uchar a1, a2, a3, a4, a5, a6, a7; x = (1000000 / y); a1 = x / 1000000; // a2 = x % 1000000 / 100000; a3 = x % 100000 / 10000; a4 = x % 10000 / 1000; a5 = x % 1000 / 100; a6 = x % 100 / 10; a7 = x % 10; // pos(0,0); //被写入数据的位置 for(i = 0; i < 6; i++) { write_data(table4[i]); } write_data(table2[a1]); write_data(table2[a2]); write_data(table2[a3]); write_data(table2[a4]); write_data(table2[a5]); write_data(table2[a6]); write_data(table2[a7]); delay(100); } void disp(ulong z) // { ulong x = z; // uchar a1, a2, a3, a4, a5, a6, a7; uchar i; a1 = x / 1000000; // a2 = x % 1000000 / 100000; a3 = x % 100000 / 10000; a4 = x % 10000 / 1000; a5 = x % 1000 / 100; a6 = x % 100 / 10; a7 = x % 10; // pos(0,0); //被写入数据的位置 for(i = 0; i < 6; i++) { write_data(table3[i]); } write_data(table2[a1]); write_data(table2[a2]); write_data(table2[a3]); write_data(table2[a4]); write_data(table2[a5]); write_data(table2[a6]); write_data(table2[a7]); delay(100); } void disp2_cycle(ulong z) // { ulong y = z; ulong x; uchar i; // uchar a1, a2, a3, a4, a5, a6, a7; x = (1000000 / y); a1 = x / 1000000; // a2 = x % 1000000 / 100000; a3 = x % 100000 / 10000; a4 = x % 10000 / 1000; a5 = x % 1000 / 100; a6 = x % 100 / 10; a7 = x % 10; // pos(1,0); //被写入数据的位置 for(i = 0; i < 6; i++) { write_data(table6[i]); } write_data(table2[a1]); write_data(table2[a2]); write_data(table2[a3]); write_data(table2[a4]); write_data(table2[a5]); write_data(table2[a6]); write_data(table2[a7]); delay(100); } void disp2(ulong z) // { ulong x = z; // uchar a1, a2, a3, a4, a5, a6, a7; uchar i; a1 = x / 1000000 ; // a2 = x % 1000000 / 100000; a3 = x % 100000 / 10000; a4 = x % 10000 / 1000; a5 = x % 1000 / 100; a6 = x % 100 / 10; a7 = x % 10; // pos(1,0); //被写入数据的位置 for(i = 0; i < 6; i++) { write_data(table5[i]); } write_data(table2[a1]); write_data(table2[a2]); write_data(table2[a3]); write_data(table2[a4]); write_data(table2[a5]); write_data(table2[a6]); write_data(table2[a7]); delay(100); } void disp3(ulong x, ulong y) // { ulong count1 = x; ulong count0 = y; // uint a1, a2, a3, a4, a5, a6, a7; uchar i; ulong cha, wucha; cha = abs(count1 - count0); wucha = (cha / 0.0001) / count1 ; //cha先放大1万倍,再与count1相除,不然就会因为是int型而被认为是0,结果就是0 //a1 = x / 1000000 + 0.2; // //a2 = x % 1000000 / 100000; //a3 = x % 100000 / 10000; a4 = wucha / 100; a5 = wucha % 100 / 10; a6 = wucha % 10 / 1; a7 = wucha % 1 / 0.1; pos(2,0); //被写入数据的位置 for(i = 0; i < 6; i++) { write_data(table7[i]); } //write_data(table2[a1]); //write_data(table2[a2]); //write_data(table2[a3]); write_data(table2[a4]); write_data(table8[0]); write_data(table2[a5]); write_data(table2[a6]); write_data(table2[a7]); write_data(table8[1]); //wirte_data('%'); //delay(100); } void disp4(ulong z) // { ulong x = z; // uchar a1, a2, a3, a4, a5, a6, a7; uchar i; a1 = x / 1000000; // a2 = x % 1000000 / 100000; a3 = x % 100000 / 10000; a4 = x % 10000 / 1000; a5 = x % 1000 / 100; a6 = x % 100 / 10; a7 = x % 10; // pos(0,0); //被写入数据的位置 for(i = 0; i < 6; i++) { write_data(table9[i]); } write_data(table2[a1]); write_data(table2[a2]); write_data(table2[a3]); write_data(table2[a4]); write_data(table2[a5]); write_data(table2[a6]); write_data(table2[a7]); delay(100); } void disp5(ulong z) // { ulong cou = z; ulong cycle; uint zkb; uint a1, a2, a3, a4, a5, a6, a7; uchar i; cycle = 1000000 / (1000000 / cou / 2); zkb = (cou / 0.01) / cycle ; //cha先放大1万倍,再与count1相除,不然就会因为是int型而被认为是0,结果就是0 //a1 = x / 1000000 + 0.2; // //a2 = x % 1000000 / 100000; //a3 = x % 100000 / 10000; a4 = zkb / 100; a5 = zkb % 100 / 10; a6 = zkb % 10 / 1; a7 = zkb % 1 / 0.1; // pos(1,0); //被写入数据的位置 for(i = 0; i < 8; i++) { write_data(table10[i]); } //write_data(table2[a1]); //write_data(table2[a2]); //write_data(table2[a3]); //write_data(table2[a4]); write_data(table2[a5]); write_data(table2[a6]); write_data(table8[0]); write_data(table2[a7]); write_data(table8[1]); delay(100); } void delay(uint z) //延时函数 { uint x, y; for (x = z; x > 0; x--) for(y = 110; y > 0; y--); } /*交换函数*/ int swap(int x) //D0与D7互换,其他同理 { uint temp; P0 = x; temp = P0_0; P0_0 = P0_7; P0_7 = temp; temp = P0_1; P0_1 = P0_6; P0_6 = temp; temp = P0_2; P0_2 = P0_5; P0_5 = temp; temp = P0_3; P0_3 = P0_4; P0_4 = temp; return P0; } void write_com(uint com) //写命令函数 { rs=0; //写命令 rs 要置 0 P0=swap(com); delay(5); en=1; delay(5); en=0; } void write_data(uint date) //写数据函数 { rs=1; //写数据 rs 要置 1 P0=swap(date); delay(5); en=1; delay(5); en=0; } void write_date(float date) //写数据函数 { rs=1; //写数据 rs 要置 1 P0=swap(date); delay(5); en=1; delay(5); en=0; } void lcd_init() //初始化函数 { wr=0; write_com(0x38); //设置点阵 write_com(0x0c); //开显示,不显示光标 write_com(0x06); //每读写一个字符地址指针加1,光标加1 write_com(0x01); //清屏 } void pos(uchar x,uchar y) //定位函数 { uchar pos; if(x==0) x=0x80; //x = 0x01; //为什么这一句和上面一句的效果一样呢? else if(x==1) x=0x90; else if(x==2) x=0x88; else if(x==3) x=0x98; pos=x+y;//光标停在第几行,第几个 write_com(pos); } void read_count() { ulong cou = 0; //ulong cycle = 0; //uint zkb; count_high = TH1; if(count_high != TH1); { //count_low = TL1; cou = TH1 * 256 + TL1; //cycle = 1000000 / cou / 2; //zkb = cou / cycle; disp4(cou); disp5(cou); } //while(count_high != TH1); //TH1 = 0; //TL1 = 0; } void t0_t1_init() { TMOD = 0X55; //设定时器1为计数模式、方式2,定时器0为定时模式,方式1 EA = 1; //总中断使能 ET1 = 1; //允许定时器1中断,下同 TR1 = 1; ET0 = 1; TR0 = 1; }