電賽校賽-單相逆變電源設計(單片機部分--C52仿真測頻+串口發送機與串口接收機)

寫在前面

承接前文的模擬部分,這次開始寫下單片機部分的仿真程序設計,本文介紹C52單片機的設置,後面將會介紹MSP430F249的具體配置。

題目

基礎部分

  • 搭建 DC-AC 電路以及檢測電路。
  • 調整系統的參數,使得輸出的交流電的頻率爲 20Hz。
  • 測量輸出交流電的頻率並顯示。

發揮部分

  • 在基礎部分 3 的基礎上,將測量到的頻率數據通過串口發送給另外一個單片
    機 2 系統,並且顯示出來。
  • 將此電源系統擴展爲三相交流電源逆變電路,並在示波器上顯示輸出波形。
    在這裏插入圖片描述

單片機部分

C52 MSP430整體程序思路介紹

本次方案採取使用 C52 單片機作爲程序部分實現的主控,一共使用了兩塊單片機 C52,一塊進行測頻然後進行串口發送,另一塊作爲串口接受機,兩塊 89C52 單片機均採用LCD12864 顯示,顯示出測量的頻率,精確到 2 位小數。
MSP430道理相同。一塊進行測頻然後進行串口發送,另一塊作爲串口接受機,採用的顯示方式不同這是oled屏幕。

程序框圖

在這裏插入圖片描述

結果展示

低ihfuheuudh
直接貼代碼吧這裏我進行了頭文件的劃分,分成了小模塊方便移植調用,這裏只給出完整的C文件,關於頭文件自行定義吧,後面附上下載連接
C52-無字庫12864仿真頻率串口發送接收.zip

C52代碼測頻+串口發送機

這裏需要使用三個定時器,也就是C51滿足不了性能要求,我們只能進行C52進行操作。這裏的晶體震盪頻率爲11.0592MHz,12M的滿足不了波特率時鐘,誤差較大,大家操作請注意。

lcd.c

#include <reg52.h>
#include "DataType.h"
#include "lcd12864.h"
  //延時
void delay(uint n)
{
  uint i;
  for(;n>0;n--)
    for(i=200;i>0;i--);
}

//判斷是否忙
void check()
{
    rs=0;  
 rw=1;   //讀 e=1;
 port=0x00;
 e=1; 
 while(busy);
 e=0;
}
//寫指令
void sendcommand(uchar command)
{
    check();
 rs=0;  //指令
 rw=0;  //寫 e=0;
 port=command;
 e=1;
 e=0; //寫入指令
}
//寫數據
void writedata(uchar dat)
{
    check();
 rs=1;    //數據
 rw=0;
 port=dat;
 e=1;
 e=0;
}
//選屏幕 0--全屏,1--左屏,2--右屏;
void select(uint n)
{
    switch(n)
 {
    case 0:cs1=0;cs2=0;break;   //低電平選中
       case 1:cs1=0;cs2=1;break;   //cs1左屏
    case 2:cs1=1;cs2=0;break;   //cs2右屏
 }  
}
//頁
void setpage(uchar page)
{
   page=page&0x07;
   page=page|0xb8;
   sendcommand(page);
}
//列
void setcolumn(uchar column)
{
   column=column&0x3f;
   column=column|0x40;
   sendcommand(column);
}
//起始行
void setline(uchar line)
{
    line=line&0x3f;
 line=line|0xc0;
 sendcommand(line);
}
//屏幕開關顯示 0--關,1--開;
void seton(uint n)
{
   n=n|0x3e;
   sendcommand(n);
}
//清屏 0--全屏,1--左屏,2--右屏;
void clear(uint n)
{
   uchar i,j;
   select(n);
   for(i=0;i<8;i++)
   {
      setpage(i);
   setcolumn(0);
   for(j=0;j<64;j++)
     writedata(0);  //置0清空
   }
}
//初始化
void init(uchar i)
{
  check();

  seton(1);
  select(0);
  //clear(0);
  setline(i);
}
//顯示漢字 16*16顯示
void show16(uchar page,uchar column,uchar screen,uchar method,uchar *str)  //頁,列,
{
  uchar i,j;
  select(screen);
  j=0;

  setpage(page);
  setcolumn(column);
  for(i=0;i<16;i++)
  {  if(method==1)   writedata(~str[j++]); //method爲顯示方式。當等於1時,反白。
     else            writedata(str[j++]);     
  }
  setpage(page+1);
  setcolumn(column);
  for(i=0;i<16;i++)
  {  if(method==1)   writedata(~str[j++]);
     else            writedata(str[j++]);     
  }
} 
//顯示數字 8*16顯示
void show8(uchar page,uchar column,uchar screen,uchar method,uchar *str)
{
  uchar i,j;
 select(screen);j=0;

 setpage(page);
 setcolumn(column);
 for(i=0;i<8;i++)
 {  if(method==1)   writedata(~str[j++]);
     else            writedata(str[j++]);     
 }
 setpage(page+1);
 setcolumn(column);
  for(i=0;i<8;i++)
  {  if(method==1)   writedata(~str[j++]);
     else            writedata(str[j++]);     
  }
}

timer.c

#include <reg52.h>		
#include "DataType.h"
#include "timer.h"
sfr T2MOD = 0xc9;  

void init_timer()
{

	TMOD |= 0X01;	//設置爲定時器計數器模式,定時器計數器0爲定時模式
	//配置定時器0
	TL0 = 0x00;		//設置定時初值
	TH0 = 0xB8;		//設置定時初值
	TR0 = 1 ;
	ET0 = 1 ;
	//設置爲定時器計數器2爲脈衝計數模式
	T2CON=0x06; //0000,0110: TR2=1,C/T2=1
 	T2MOD=0x00; //0000,0000: 加計數,
 	TH2=0x00;  //給定時器T2賦初值        
 	TL2=0x00;
	ET2 = 1 ;
	EA = 1;//開總中斷
}



main.c

#include <reg52.h>
#include "DataType.h"
#include "lcd12864.h"
#include "timer.h"
#include "zk.h"
#include "uart.h"
#include "stdio.h"
int i = 0 , t = 0 ,j=0;	//計數器溢出的存儲變量
ulint frency; 	//頻率值
ulint frency1; 	//頻率值
uint d;
uchar tmp1[4];
void calculate() ;	//計算頻率模塊

/**************************
        顯示頻率函數
**************************/
void dispaly_f1() 
{
	int show1[6] ;
	int six_number1  = frency1/100000 ;
	int five_number1 = frency1/10000%10;
	int four_number1 = frency1/1000%10 ;
	int three_number1= frency1/100%10 ;
	int two_number1  = frency1/10%10 ; 
	int one_number1  = frency1%10 ;
	show1[5] = one_number1; 
	show1[4] = two_number1; 
	show1[3] = three_number1 ; 
	show1[2] = four_number1 ; 
	show1[1] = five_number1 ;
	show1[0] = six_number1  ;
	show16(4,0,1,0,hz[2]);    //寫數據
	show16(4,16,1,0,hz[3]);    //寫數據
	show8(4,32,1,0,sign[0]);    //寫數據
	
	show8(4,40,1,0,num[show1[0]]);    //寫數據
	show8(4,48,1,0,num[show1[1]]);    //寫數據
	show8(4,56,1,0,num[show1[2]]);    //寫數據
	
	show8(4,0,2,0,num[show1[3]]);    //寫數據
	show8(4,8,2,0,num[show1[4]]);    //寫數據
	show8(4,16,2,0,num[show1[5]]);    //寫數據
	show8(4,24,2,0,sign[1]);    //寫數據
	show8(4,32,2,0,sign[2]);    //寫數據
	/**/
}

void delayms(uint n)
{
 uchar i;
 while(n--)
 {
   for(i = 0;i < 120;i++);
 }
}

void main()
{
	init_timer();
	init_uart();
	clear(0);
	show16(0,0,1,0,hz[5]);    //寫數據
	show16(0,16,1,0,hz[6]);    //寫數據
	show16(0,32,1,0,hz[7]);    //寫數據
	show16(0,48,1,0,hz[8]);    //寫數據
	show16(0,0,2,0,hz[9]);    //寫數據
	delayms(200);
  //send("Receiving from ...\r\n");    測試
	//delayms(200);
	while(1)
 {
	 dispaly_f1();
	 sprintf((char *)tmp1,"%4.0lu",frency1);//僅僅發送數據
	 send(tmp1);//
	 
	 delayms(50);
 }
}

void time0() interrupt 1
{
  TL0 = 0x00;		//設置定時初值
	TH0 = 0xB8;		//設置定時初值
	if( ++t >= 50 ) {		//使用多次中斷實現1s的延時
	 TR2 = 0 ; 		//爲了計數的準確性,在計算的時候將計數器1關閉
	 calculate() ;
	 
	 t = 0 ; 
	 TH2 = 0  ;		//清空計數器中的值,防止對下一個週期計數產生影響
	 TL2 = 0 ;
	 TR2 = 1 ;		//最後打開中斷
	 
	 }
}

void time2() interrupt 5
{
	j++ ;
}
void calculate()
{ 
	frency1 = j*65535 + TH2*256 + TL2 ; 
	//i = 0 ; 
	j = 0 ;	//將溢出的次數清零,爲下一次計數做準備
}

uart.c

#include <reg52.h>		//這裏的晶體震盪頻率爲11.0592MHz
#include "DataType.h"
#include "uart.h"

void init_uart()
{
	//配置定時器1
	TMOD |= 0x20;	//模式2 8位自動重載模式 溢出時,將TH1裝入TL1
	TH1 = 0xfd;		//波特率:9600
	TL1 = TH1;
	PCON = 0x00;	
	SCON = 0x50; 	//方式1(定時器1溢出率)允許接收
  TR1=1;//開定時器1中斷
	
}

void send(uchar *c)
{
 while(*c != '\0')
 {
  SBUF=*c;
  c++;
  while(TI==0);
  TI=0;
	//delay(5);
 }
}

字庫頭文件

對於proteus的顯示仿真,字庫需要自己構建,這裏給出我用的這個

#ifndef  __ZK_H
#define  __ZK_H
#include "DataType.h"
extern uchar code hz[][32]={
{0x00,0x00,0xF8,0x88,0x88,0x88,0x88,0xFF,0x88,0x88,0x88,0x88,0xF8,0x00,0x00,0x00,
0x00,0x00,0x1F,0x08,0x08,0x08,0x08,0x7F,0x88,0x88,0x88,0x88,0x9F,0x80,0xF0,0x00},/*"電",0*/

{0x00,0x00,0xFE,0x02,0x82,0x82,0x82,0x82,0xFA,0x82,0x82,0x82,0x82,0x82,0x02,0x00,
0x80,0x60,0x1F,0x40,0x40,0x40,0x40,0x40,0x7F,0x40,0x40,0x44,0x58,0x40,0x40,0x00},/*"壓",1*/

{0x40,0x7C,0x40,0x7F,0x48,0x48,0x40,0xF2,0x12,0x1A,0xD6,0x12,0x12,0xF2,0x02,0x00,
0x90,0x8E,0x40,0x4F,0x20,0x1E,0x80,0x4F,0x20,0x18,0x07,0x10,0x20,0x4F,0x80,0x00},/*"頻",2*/

{0x00,0x14,0xA4,0x44,0x24,0x34,0xAD,0x66,0x24,0x94,0x04,0x44,0xA4,0x14,0x00,0x00,
0x08,0x09,0x08,0x08,0x09,0x09,0x09,0xFD,0x09,0x09,0x0B,0x08,0x08,0x09,0x08,0x00},/*"率",3*/

{0x10,0x60,0x02,0x8C,0x00,0x44,0x64,0x54,0x4D,0x46,0x44,0x54,0x64,0xC4,0x04,0x00,
0x04,0x04,0x7E,0x01,0x80,0x40,0x3E,0x00,0x00,0xFE,0x00,0x00,0x7E,0x80,0xE0,0x00},/*"流",4*/

{0x00,0x00,0x3C,0x24,0x24,0x24,0x24,0xFF,0x24,0x24,0x24,0x24,0x3C,0x00,0x00,0x00,
0x00,0x1F,0x09,0x09,0x09,0x09,0x09,0xFF,0x09,0x09,0x09,0x09,0x09,0x1F,0x00,0x00},/*"串",2*/

{0x00,0x00,0xFC,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0xFC,0x00,0x00,0x00,
0x00,0x00,0x7F,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7F,0x00,0x00,0x00},/*"口",3*/

{0x00,0x00,0x18,0x16,0x10,0xD0,0xB8,0x97,0x90,0x90,0x90,0x92,0x94,0x10,0x00,0x00,
0x00,0x20,0x10,0x8C,0x83,0x80,0x41,0x46,0x28,0x10,0x28,0x44,0x43,0x80,0x80,0x00},/*"發",4*/

{0x40,0x40,0x42,0xCC,0x00,0x88,0x89,0x8E,0x88,0xF8,0x88,0x8C,0x8B,0x88,0x80,0x00,
0x00,0x40,0x20,0x1F,0x20,0x40,0x50,0x48,0x46,0x41,0x42,0x44,0x58,0x40,0x40,0x00},/*"送",5*/

{0x10,0x10,0xD0,0xFF,0x90,0x10,0x00,0xFE,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,
0x04,0x03,0x00,0xFF,0x00,0x83,0x60,0x1F,0x00,0x00,0x00,0x3F,0x40,0x40,0x78,0x00},/*"機",6*/

};

extern uchar code num[][16]={
{0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00},
//"0",0

{0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00},
//"1",1

{0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00},
//"2",2

{0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00},
//"3",3

{0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00},
//"4",4

{0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00},
//"5",5

{0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00},
//"6",6

{0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00},
//"7",7

{0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00},
//"8",8

{0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00} //"9",9

};

extern uchar code sign[][16]={
	
{0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00},/*":",0*/

{0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20},/*"H",1*/

{0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00},/*"Z",2*/

{0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,0x20,0x3F,0x01,0x3E,0x01,0x3F,0x20,0x00},/*"M",3*/

{0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00},/*"V",4*/

{0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F},/*"m",5*/

{0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x03,0x0C,0x30,0x0C,0x03,0x00,0x00},/*"v",6*/


};

#endif

DATATYPE_H

#ifndef  __DATATYPE_H
#define  __DATATYPE_H

#define uint unsigned int
#define uchar unsigned char
#define ushort unsigned short
#define ulint unsigned long int
#define ldouble long double

#endif

C52代碼串口接收機

lcd.c

同剛剛

uart.c

#include <reg52.h>		//這裏的晶體震盪頻率爲11.0592MHz
#include "DataType.h"
#include "uart.h"

void init_uart()
{
	//配置定時器1
	TMOD |= 0x20;	//模式2 8位自動重載模式 溢出時,將TH1裝入TL1
	TH1 = 0xfd;		//波特率:9600
	TL1 = TH1;
	PCON = 0x00;	
	SCON = 0x50; 	//方式1(定時器1溢出率)允許接收
  TR1=1;//開定時器1中斷
	EA = 1;//開總中斷
	ES = 1;               //開串口接收中斷
}
//發送
void send(uchar *c)
{
	
 while(*c != '\0')
 {
  SBUF=*c;
  c++;
  while(TI==0);
  TI=0;
 }
}



	

main.c

#include <reg52.h>
#include "DataType.h"
#include "lcd12864.h"
#include "zk.h"
#include "uart.h"
#include "stdio.h"
#include "string.h"
uint k=0;
uchar Read_buff[4];   //設置接收字符串緩存

uint buff_size = 5;   //設置緩存大小
uint dat_count;    //單次接收數據總數
uint buff_lenght;  //計算接收數據長
void delayms(uint n)
{
 uchar i;
 while(n--)
 {
   for(i = 0;i < 120;i++);
 }
}
//字符發送函數
void putchar1(unsigned char data1)  
{
  SBUF = data1;               //將待發送的字符送入發送緩衝器
 while(TI == 0);            //等待發送完成
 TI = 0;                     //發送中斷標誌請0
}

//字符串發送函數
void putstring(unsigned char *dat)
{
  while(*dat != '\0')           //判斷字符串是否發送完畢
 {
   putchar1(*dat);        //發送單個字符
  dat++;                 //字符地址加1,指向先下一個字符
  //delay(5);
 }
}

void main()
{
	//init_uart();
	SCON = 0x50;           //串口方式1 ,允許接收
 TMOD = 0x20;           //T1工作於方式2
 PCON = 0x00;           //波特率不倍增
 TL1 = 0xfd;              //波特率設置
 TH1 = 0xfd;            //
 EA = 1;                    //開總中斷
 ES = 1;               //開串口接收中斷
 //TI = 0; 
 TR1 = 1;             //定時器開啓
	 delay(200);
 putstring("Receiving from 8051...\r\n");         //串口向終端發送字符串,結尾處回車換行
 putstring("----------------------\r\n"); 
 delay(50);
	clear(0);
	//界面
	show16(0,0,1,0,hz[5]);    //寫數據
	show16(0,16,1,0,hz[6]);    //寫數據
	show16(0,32,1,0,hz[10]);    //寫數據
	show16(0,48,1,0,hz[11]);    //寫數據
	show16(0,0,2,0,hz[9]);    //寫數據
	show16(4,0,1,0,hz[2]);    //寫數據
	show16(4,16,1,0,hz[3]);    //寫數據
	show8(4,32,1,0,sign[0]);    //寫數據
	delayms(100);
    //send("Receiving from ...\r\n");    測試
	//delayms(200);
	while(1)
 {
	 show16(4,0,1,0,hz[2]);    //寫數據
	 show16(4,16,1,0,hz[3]);    //寫數據
	 show8(4,32,1,0,sign[0]);    //寫數據
	 show8(4,24,2,0,sign[1]);    //寫數據
	 show8(4,32,2,0,sign[2]);    //寫數據
	 if(dat_count==4){
			dat_count=0;
			show8(4,40,1,0,num[Read_buff[0]-'0']);    //寫數據
			show8(4,48,1,0,num[Read_buff[1]-'0']);    //寫數據
			show8(4,56,1,0,num[Read_buff[2]-'0']);    //寫數據
			show8(4,0,2,0,num[Read_buff[3]-'0']);    //寫數據
			ES= 0;
			putstring(Read_buff);
			ES=1;
		 }
 }
}
/*


	
void Usart() interrupt 4
{
        uchar receiveData;
        receiveData=SBUF;//出去接收到的數據
				
        Receive(receiveData);
        RI = 0;//清除接收中斷標誌位
        SBUF=receiveData;//將接收到的數據放入到發送寄存器
        while(!TI);//等待發送數據完成
        TI=0;//清除發送完成標誌位
}



*/

void Receive(char x)
  {
		Read_buff[k]=x;
		
		k++;
		if(k==4){
			k=0;
			show8(4,40,1,0,num[Read_buff[3]-'0']);    //寫數據
			show8(4,48,1,0,num[Read_buff[2]-'0']);    //寫數據
			show8(4,56,1,0,num[Read_buff[1]-'0']);    //寫數據
			show8(4,0,2,0,num[Read_buff[0]-'0']);    //寫數據
			ES= 0;
			putstring(Read_buff);
			ES=1;
		 }
  }

/*
void revdata(void) interrupt 4
{
  unsigned char temp;
 if(RI == 0) return;         //如果沒有接收中斷標誌,返回
 ES = 0;            //關閉串口中斷
 RI = 0;            //清串行中斷標誌位
 temp = SBUF;        //接收緩衝器中的字符
 Receive(temp);
 ES = 1;                 //開啓串口中斷
}
*/
/*中斷函數,中斷函數完全用作了接收函數*/
void serial()interrupt 4
{
    uchar temp;uint i;
    if(RI == 1)
    {
        temp = SBUF;
        RI = 0;
        if(dat_count < buff_size && temp != '\0')  //判斷接收結束
       {
					
            if(dat_count == 0)
                for(i = 0; i < buff_size;i ++)        //清空接收緩存
                    Read_buff[i] = ' ';
						if(temp==' ')
							Read_buff[dat_count] = '0';
						else
							Read_buff[dat_count] = temp;              //將數據存入存儲
            dat_count ++;
            buff_lenght = dat_count;                  //獲取接收字符串長度
       }
        else
        {
            dat_count = 0;
        }
    }
}

工程鏈接

包括C52測頻串口發送機、串口接收機以及proteus8.6仿真,上文會操作的建議自己來試試,不會的可以下載工程,修改參考,時間比較緊,製作可能有些部分不太合理,歡迎大家指教
工程鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章