在Proteus仿真软件里面使用STC89C52实现指定频率的AC信号的测频、显示、双机通信。

一.原理图部分

整体的电路图如示:

DC-AC电路部分的输出就使用信号源直接模拟了。
原理图如下:

运行结果如下:

可以准确测量出结果,并在LCD上显示,单片机1测量到频率后通过串口发送给单片机2,然后在单片机2的LCD上再次显示。

二.源码部分

单片机1


/*单片机1功能:
*1.测量AC的频率20Hz,T0检测上升沿、T1进行计时
*2.LED显示实时测量频率
*3.与单片机2串口通信,T2提供波特率
*晶振频率:11.0592MHz
*/ #include <reg52.h>
#include <stdio.h>
#include <intrins.h>
#include <string.h> #define uint unsigned int
#define uchar unsigned char sfr T2MOD=0XC9; //寄存器T2MOD定义 /********************* LCD驱动 ************************************/
/* LCD引脚说明 */
sbit RS = P2^0;
sbit RW = P2^1;
sbit EN = P2^2; /*说明:延时函数
*参数:延时的ms数
*/
void DelayMS(uint ms)
{
uchar i;
while(ms--)
{
for(i=0;i<120;i++);
}
} /*说明:LCD读
*参数:返回读取的值
*/
uchar Read_LCD_State()
{
uchar state;
RS=0;
RW=1;
EN=1;
DelayMS(1);
state=P0;
EN = 0;
DelayMS(1);
return state;
} /*说明:LCD忙判断
*参数:无
*/
void LCD_Busy_Wait()
{
while((Read_LCD_State()&0x80)==0x80);
DelayMS(5);
} /*说明:向LCD写1Byte数据
*参数:写入的数据
*/
void Write_LCD_Data(uchar dat)
{
LCD_Busy_Wait();
RS=1;
RW=0;
EN=0;
P0=dat;
EN=1;
DelayMS(1);
EN=0;
} /*说明:LCD写命令
*参数:cmd:写入的命令
*/
void Write_LCD_Command(uchar cmd)
{
LCD_Busy_Wait();
RS=0;
RW=0;
EN=0;
P0=cmd;
EN=1;
DelayMS(1);
EN=0;
} /*说明:LCD初始化
*参数:无
*/
void Init_LCD()
{
Write_LCD_Command(0x38);
DelayMS(1);
Write_LCD_Command(0x01);
DelayMS(1);
Write_LCD_Command(0x06);
DelayMS(1);
Write_LCD_Command(0x0c);
DelayMS(1);
} /*说明:LCD定位显示
*参数:0X00第一行 0X40第二行
*/
void Set_LCD_POS(uchar p)
{
Write_LCD_Command(p|0x80);
} /*说明:LCD显示函数
*参数:p:位置信息
* *s:显示的字符串(一行只能显示16个字符)
*/
void Display_LCD_String(uchar p,uchar *s)
{
uchar i;
Set_LCD_POS(p);
for(i=0;i<16;i++)
{
/* 写数据 */
Write_LCD_Data(s[i]);
DelayMS(1);
}
} /******************************* 测频驱动 *************************************************/
long uint pulse=0; //T0计数的方波的个数;
long uint freq=0; //输入信号的频率
uchar temp=0; //临时变量 /*说明:定时器/计数器初始化函数
*T0的工作方式为16位计数器模式,用来记录上升沿
*T1的工作方式为16位定时器模式,用来计时
*
*参数:无
*/
void Time_Init()
{
EA=1; //打开全局中断
TMOD |= 0x15; //T0:16位计数器模式 T1:16位定时器模式 TH0 = 0xff; //计数器0的初值
TL0 = 0xff; //计数器0的初值
ET0=1; //允许计数器0中断
TR0=1; //打开计数器0,开始计数 TH1 = 0x4b; //定时器1的初值
TL1 = 0xff; //定时器1的初值
ET1=1; //允许定时器1中断
TR1 = 1; //打开定时器1,开始计数
} /*说明:T0的中断服务函数,用来计数脉冲数,每一个方波脉冲,计数器进入中断,脉冲数+1
*参数:无
*/
void ISQ_timer0(void) interrupt 1
{
TR0 = 0;
pulse++;
TH0 = 0xff;
TL0 = 0xff;
TR0 = 1;
} /*说明:T1的中断服务函数,每次中断代表50ms,测量20次中断(1s)的脉冲数就是频率
*参数:无
*/
void ISQ_time1() interrupt 3
{
TH1 = 0x4b; //11.0592MHz,50ms定时的重装值
TL1 = 0xff;
temp++;
if(temp==20)
{
TR0 = 0; //进入处理时,关闭
TR1 = 0;
temp=0;
freq=pulse;
pulse=0; //将脉冲数清零,重新计数
TR0 = 1; //处理完毕,打开
TR1 = 1;
}
} /************************************ T2uart *************************************************/ /*说明:uart配置,T2作为波特率发生定时器
*参数:无
*/
void uart_config(void)
{ T2MOD = 0x01; //自动重载
T2CON = 0x30; //T2用做发送接收时钟
TH2 = 0xFF; //9600波特率,11.0592Mhz晶振
TL2 = 0xDC;
RCAP2H = 0xFF;
RCAP2L = 0xDC;
SCON = 0x50; //串口方式1,1个起始位,1个停止位,8位数据,可变波特率
PCON = 0X00; //波特率不加倍
TR2 = 1; //启动T2
ES = 1; //开串口中断
EA = 1; //开总中断
} /*说明:uart发送一个字符
*参数:byte:发送的字符
*/
void uart_send_byte( uchar byte )
{
ES=0;
SBUF=byte;
while(!TI);
TI=0;
ES=1;
} /*说明:uart发送字符串,固定长度为16*uchar
*参数:*str:发送的字符串首地址
*/
void uart_send_str( uchar *str )
{
uint i=0;
for( i=0;i<16;i++ )
{
uart_send_byte(str[i]); }
} void main()
{
uchar temp[16]; //定义字符显示缓存数组 Time_Init(); //T0、T1初始化
uart_config(); //uart初始化,主要是T2初始化波特率
Init_LCD(); //LCD初始化 while(1)
{ sprintf(temp,"FREQ:%08.0fHz",(float)freq);
Display_LCD_String(0X40,temp); uart_send_str(temp);
}
}

单片机2

本来单片机2还负责给DC-AC电路产生控制信号的,在这里我忽略了DC-AC电路部分,所以控制信号的代码可有可无。

/*单片机2功能:
*1.与单片机1进行串口通讯,接收测量的AC频率
*2.LED显示实时单片机1传回的测量频率
*3.为DC-AC逆置电路提供信号
*晶振频率:11.0592MHz
*/
#include <reg52.h>
#include <stdio.h>
#include <intrins.h>
#include <string.h> #define uint unsigned int
#define uchar unsigned char
#define uint8_t uint /********************* 控制信号发生 ************************************/
//为DC-AC电路提供稳定的20Hz脉冲信号
sbit O1_4 = P2^3 ;
sbit O2_3 = P2^4; sbit G1=P1^2;
sbit G2=P1^3;
sbit G3=P1^4;
sbit G4=P1^5;
sbit G5=P1^6;
sbit G6=P1^7;
unsigned int time1;
unsigned int time2; /*说明:T0初始化,利用T0输出PWM脉冲信号
*参数:无
*/
void Timer0_Init(void) //1毫秒@11.0592
{
TMOD |= 0x01;
TH0 = 0xfc;
TL0 = 0x66;
TF0 = 0;
EA = 1;
TR0 = 1;
ET0 = 1; } /*说明:T0中断服务函数,产生PWM脉冲信号
*参数:无
*/
void time0() interrupt 1
{
TH0=0xfc;
TL0=0x66;
time1++;
time2++;
/* 单相 */
if((time1>=0)&&(time1<=25)){O1_4=1;O2_3=0;}
if((time1>25)&&(time1<=50)){O1_4=0;O2_3=1;}
if(time1>50)time1=0; /* 三相 */
if(time2>0&&time2<=8){G1=1;G2=0;G3=0;G4=0;G5=1;G6=1;}
if(time2>8&&time2<=16){G1=1;G2=1;G3=0;G4=0;G5=0;G6=1;}
if(time2>16&&time2<=24){G1=1;G2=1;G3=1;G4=0;G5=0;G6=0;}
if(time2>24&&time2<=32){G1=0;G2=1;G3=1;G4=1;G5=0;G6=0;}
if(time2>32&&time2<=40){G1=0;G2=0;G3=1;G4=1;G5=1;G6=0;}
if(time2>40&&time2<=48){G1=0;G2=0;G3=0;G4=1;G5=1;G6=1;}
if(time2>48)time2=0; }//50ms的周期 /********************* LCD驱动 ************************************/
/* LCD引脚 */
sbit RS = P2^0;
sbit RW = P2^1;
sbit EN = P2^2; /*说明:延时函数
*参数:延时的ms数
*/
void DelayMS(uint ms)
{
uchar i;
while(ms--)
{
for(i=0;i<120;i++);
}
} /*说明:LCD读
*参数:返回读取的值
*/
uchar Read_LCD_State()
{
uchar state;
RS=0;
RW=1;
EN=1;
DelayMS(1);
state=P0;
EN = 0;
DelayMS(1);
return state;
} /*说明:LCD忙判断
*参数:无
*/
void LCD_Busy_Wait()
{
while((Read_LCD_State()&0x80)==0x80);
DelayMS(5);
} /*说明:向LCD写1Byte数据
*参数:写入的数据
*/
void Write_LCD_Data(uchar dat)
{
LCD_Busy_Wait();
RS=1;
RW=0;
EN=0;
P0=dat;
EN=1;
DelayMS(1);
EN=0;
} /*说明:LCD写命令
*参数:cmd:写入的命令
*/
void Write_LCD_Command(uchar cmd)
{
LCD_Busy_Wait();
RS=0;
RW=0;
EN=0;
P0=cmd;
EN=1;
DelayMS(1);
EN=0;
} /*说明:LCD初始化
*参数:无
*/
void Init_LCD()
{
Write_LCD_Command(0x38);
DelayMS(1);
Write_LCD_Command(0x01);
DelayMS(1);
Write_LCD_Command(0x06);
DelayMS(1);
Write_LCD_Command(0x0c);
DelayMS(1);
} /*说明:LCD定位显示
*参数:0X00第一行 0X40第二行
*/
void Set_LCD_POS(uchar p)
{
Write_LCD_Command(p|0x80);
} /*说明:LCD显示函数
*参数:p:位置信息
* *s:显示的字符串(一行只能显示16个字符)
*/
void Display_LCD_String(uchar p,uchar *s)
{
uchar i;
Set_LCD_POS(p);
for(i=0;i<16;i++)
{
/* 写数据 */
Write_LCD_Data(s[i]);
DelayMS(1);
}
} /************************************ T1uart *************************************************/ /*说明:uart初始化函数,T1为uart提供9600波特率
*参数:无
*/
void uart_config(void)
{
TMOD |= 0x20; //设置定时器1的工作方式2---8位自动装填
SCON = 0x50;
TH1 = 0xfd; //设置初始值:使比特率为9600bps
TL1 = 0xfd;
PCON = 0x00; //SMOD=0,不加倍
EA = 1; //打开总中断
ES = 1; //打开串口通讯中断
TR1 = 1; //打开定时器中断开关
} uchar Rx_Str[16]={0}; //接收缓存
uint state; //接收状态:1:正在接收 0:接收完毕
volatile uint i=0;
/*说明:uart中断处理函数,进行解析数据帧
*参数:无
*/
void uart_receive() interrupt 4
{
uchar num;
if(1==RI)
{
RI=0; //清除标志位
num=SBUF; //从计算机接收数据,赋给num
if( num == 'F' ) //解析帧头
{
state = 1;
}
if( Rx_Str[i-1] == 'z' ) //解析帧尾
{
state = 0;
i=0;
} if( 1 == state ) //缓存数据
{
Rx_Str[i++] = num;
} }
} void main()
{
Timer0_Init(); //T0初始化,产生脉冲信号
uart_config(); //uart初始化,接收串口数据
Init_LCD(); //LCD初始化,显示接收的数据帧 while(1)
{
Display_LCD_String(0X40,Rx_Str);
}
}

Proteus仿真—51单片机实现AC信号测频、显示、双机通信的更多相关文章

  1. Proteus仿真MSP430单片机的若干问题记录

    1.支持的具体型号: P7.8: Proteus8.9: Proteus8.9能够支持的类型明显要多于Proteus7.8.但是对于仿真而言,目前个人还是觉得Proteus7.8更稳定.这也是目前能用 ...

  2. 51单片机 | 实现SMC1602液晶屏显示实例

    ———————————————————————————————————————————— LCD1602 - - - - - - - - - - - - - - - - - - - - - - - - ...

  3. &lt;模拟电子学习1&gt;Multisim 12.0 结构和仿真51最小的单芯片系统

    周围环境: 系统环境: win7 64位置 软件平台:Multisim 12.0 目的: 刚毕业,可是模电知识也忘得差点儿相同了,加之自己想搞搞硬件设计.假设仅仅是看模电书.不实践,还是终觉浅.当做兴 ...

  4. 【零基础】入门51单片机图文教程(Proteus+Keil)

    参考资料: https://www.jianshu.com/p/88dfc09e7403 https://blog.csdn.net/feit2417/article/details/80890218 ...

  5. 2017.11.18 手把手教你学51单片机-点亮LED

    In Doing We Learning 在操作中学习.如果只是光看教程,没有实际的操作,对编程语言的理解很空泛,所以决定从单片机中学习C语言. #include<reg52.h>     ...

  6. 《例说51单片机(C语言版)(第3版)》——1-3 认识MCS-51的存储器结构

    本节书摘来异步社区<例说51单片机(C语言版)(第3版)>一书中的第1章,第1.3节,作者:张义和,王敏男,许宏昌,余春长,更多章节内容可以访问云栖社区"异步社区"公众 ...

  7. 51单片机头文件reg51.h详解

    转自:http://www.51hei.com/mcu/2670.html 我们在用c语言编程时往往第一行就是头文件,51单片机为reg51.h或reg52.h,51单片机相对来说比较简单,头文件里面 ...

  8. [新概念51单片机C语言教程·郭天祥] 1、 基础知识必备

    目录: 单片机的大致介绍         1-1.通俗定义         1-2.51系列产品         1-3.标号意思         1-4.引脚介绍         1-5.用C语言开 ...

  9. 关于51单片机P0口的结构及上拉问题

    1.P0作为地址数据总线时,V1和V2是一起工作的,构成推挽结构.高电平时,V1打开,V2截止:低电平时,V1截止,V2打开.这种情况下不用外接上拉电阻.而且,当V1打开,V2截止,输出高电平的时候, ...

随机推荐

  1. 大数据-Hadoop 本地运行模式

    Grep案例 1. 创建在hadoop-2.7.2文件下面创建一个input文件夹 [atguigu@hadoop101 hadoop-2.7.2]$ mkdir input 2. 将Hadoop的x ...

  2. vim下出现^M怎么解决

    将window下的文本文件上传到linux上,在读取数据文件时,在每一行数据后会出现^M字符.   为什么会出现这种情况呢: 因为windows.linux.os系统的换行符标准不同: 先了解下概念, ...

  3. 欧拉函数&筛法 模板

    https://blog.csdn.net/Lytning/article/details/24432651    记牢通式 =x((p1-1)/p1) * ((p2-1)/p2)....((pn-1 ...

  4. Window server 2016 搭建Java Web环境

    系统下载 下载种子(迅雷下载): ed2k://|file|cn_windows_server_2016_updated_feb_2018_x64_dvd_11636703.iso|629426585 ...

  5. QT从入门到入土(三)——信号和槽机制

    摘要 信号槽是 Qt 框架引以为豪的机制之一.所谓信号槽,实际就是观察者模式.当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号 (signal).这种发出是没有目的的,类似广播 ...

  6. Python基础4--数据类型

    一.数据类型是什么鬼? 计算机顾名思义就是可以做数学计算的机器,因此,计算机程序理所当然地可以处理各种数值.但是,计算机能处理的远不止数值,还可以处理文本.图形.音频.视频.网页等各种各样的数据,不同 ...

  7. SpringBoot总结之事务和AOP

    一.事务 在Spring Boot中,当我们使用了spring-boot-starter-jdbc或spring-boot-starter-data-jpa依赖的时候,框架会自动默认分别注入DataS ...

  8. springboot-6-springSecurity

    一.Spring Security的基本配置 安全需要在设计网站之初就需要做好设计 可以做到: 功能权限 访问权限 菜单权限 这些权限虽然用拦截器过滤器也能实现,但是很麻烦,所以我们一般使用框架实现 ...

  9. 一张图概括mysql的各种join用法

  10. 第2天 第一个程序&IDEA安装&Java基础语法

    第一个程序 Hello,World! 随便新建一个文件夹,存放代码 新建一个Java文件 文件后缀名为java Hello.java [注意点]系统可能没有显示后缀名,必须手动打开 编写代码 publ ...