Proteus仿真—51单片机实现AC信号测频、显示、双机通信
在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信号测频、显示、双机通信的更多相关文章
- Proteus仿真MSP430单片机的若干问题记录
		1.支持的具体型号: P7.8: Proteus8.9: Proteus8.9能够支持的类型明显要多于Proteus7.8.但是对于仿真而言,目前个人还是觉得Proteus7.8更稳定.这也是目前能用 ... 
- 51单片机 | 实现SMC1602液晶屏显示实例
		———————————————————————————————————————————— LCD1602 - - - - - - - - - - - - - - - - - - - - - - - - ... 
- <模拟电子学习1>Multisim 12.0 结构和仿真51最小的单芯片系统
		周围环境: 系统环境: win7 64位置 软件平台:Multisim 12.0 目的: 刚毕业,可是模电知识也忘得差点儿相同了,加之自己想搞搞硬件设计.假设仅仅是看模电书.不实践,还是终觉浅.当做兴 ... 
- 【零基础】入门51单片机图文教程(Proteus+Keil)
		参考资料: https://www.jianshu.com/p/88dfc09e7403 https://blog.csdn.net/feit2417/article/details/80890218 ... 
- 2017.11.18  手把手教你学51单片机-点亮LED
		In Doing We Learning 在操作中学习.如果只是光看教程,没有实际的操作,对编程语言的理解很空泛,所以决定从单片机中学习C语言. #include<reg52.h> ... 
- 《例说51单片机(C语言版)(第3版)》——1-3 认识MCS-51的存储器结构
		本节书摘来异步社区<例说51单片机(C语言版)(第3版)>一书中的第1章,第1.3节,作者:张义和,王敏男,许宏昌,余春长,更多章节内容可以访问云栖社区"异步社区"公众 ... 
- 51单片机头文件reg51.h详解
		转自:http://www.51hei.com/mcu/2670.html 我们在用c语言编程时往往第一行就是头文件,51单片机为reg51.h或reg52.h,51单片机相对来说比较简单,头文件里面 ... 
- [新概念51单片机C语言教程·郭天祥] 1、 基础知识必备
		目录: 单片机的大致介绍 1-1.通俗定义 1-2.51系列产品 1-3.标号意思 1-4.引脚介绍 1-5.用C语言开 ... 
- 关于51单片机P0口的结构及上拉问题
		1.P0作为地址数据总线时,V1和V2是一起工作的,构成推挽结构.高电平时,V1打开,V2截止:低电平时,V1截止,V2打开.这种情况下不用外接上拉电阻.而且,当V1打开,V2截止,输出高电平的时候, ... 
随机推荐
- base64文件解码
			$str = str_replace(' ', '+', $str); //替换空字符串为+$str = str_replace('\n', '',$str); //置空换行符$str = str_r ... 
- Acunetix敏感的数据泄露–泄露如何发生
			术语"敏感数据暴露"是指允许未授权方访问存储或传输的敏感信息,例如信用卡号或密码.全球范围内大多数重大安全漏洞都会导致某种敏感的数据泄露. Acunetix利用攻击漏洞(例如Web ... 
- .Net5 IdentityServer4下SqlServer和Mysql数据迁移
			1.概念 以下概念从官网整理的,我也是看官网一步一步学习的 官网地址 https://identityserver4.readthedocs.io/en/latest/index.html 1.1 I ... 
- bat自动创建快捷方式并更换图标
			1 :: 此脚本主要的作用创建1.自动创建快捷方式:2.自动更换快捷方式图标 2 @echo off 3 >nul 2>&1 "%SYSTEMROOT%\system32 ... 
- 前端-Vue基础1
			Vue核心思想:只要改变数据,页面就会发生改变 1.引入vue 1.下载vue.js 2.在script标签的src属性中,引入vue.js <script src="js/vue.j ... 
- C++ 标准模板库(STL)——迭代器(iterators)的用法及理解
			C++ STL中迭代器(iterators)用于遍历对象集合的元素.由于容器大小随着插入删除等操作动态改变,无法像静态数组那样获取数组长度然后遍历容器里的所有元素:这时就需要迭代器,每次从容器内第一个 ... 
- 小刻也能看懂的Unraid系统使用手册:基础篇
			小刻也能看懂的Unraid系统使用手册 基础篇 Unraid系统简介 Unraid 的本体其实是 Linux,它主要安装在 NAS 和 All in One 服务器上,经常可以在 Linus 的视频里 ... 
- Leetcode 春季打卡活动 第一题:225. 用队列实现栈
			Leetcode 春季打卡活动 第一题:225. 用队列实现栈 Leetcode 春季打卡活动 第一题:225. 用队列实现栈 解题思路 这里用了非常简单的思路,就是在push函数上做点操作,让队头总 ... 
- Word中的代码怎样语法高亮
			在平常我们粘贴代码到Word中的时候,经常会遇到代码粘贴到Word中后没有语法高亮,看着很乱很不友好,Word自带的样式---语法使用着也不尽人意, 网上有很多做法可以使得在插入在Word中的代码能够 ... 
- SQL SERVER 按时间计算每天某值的平均值
			在报表需求中,有针对求每天按时间分配数据的平均值,在经过查找后,找到一种方法,供参考. 1.新建视图 2.编写语句 SELECT TOP (100) PERCENT AVG(dbo.漕盈日运行.CO ... 
