在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);
}
}