电赛校赛-三相逆变电源设计(单片机部分--C52仿真测频+串口发送机与串口接收机)

简介: 电赛校赛-三相逆变电源设计(单片机部分--C52仿真测频+串口发送机与串口接收机)

写在前面


承接前文的模拟部分,这次开始写下单片机部分的仿真程序设计,本文介绍C52单片机的设置,后面将会介绍MSP430F249的具体配置。

题目


基础部分


  • 搭建 DC-AC 电路以及检测电路。
  • 调整系统的参数,使得输出的交流电的频率为 20Hz。
  • 测量输出交流电的频率并显示。

发挥部分


  • 在基础部分 3 的基础上,将测量到的频率数据通过串口发送给另外一个单片
    机 2 系统,并且显示出来。
  • 将此电源系统扩展为三相交流电源逆变电路,并在示波器上显示输出波形。

image.png

image.png

单片机部分


C52 MSP430整体程序思路介绍


本次方案采取使用 C52 单片机作为程序部分实现的主控,一共使用了两块单片机 C52,一块进行测频然后进行串口发送,另一块作为串口接受机,两块 89C52 单片机均采用LCD12864 显示,显示出测量的频率,精确到 2 位小数。

MSP430道理相同。一块进行测频然后进行串口发送,另一块作为串口接受机,采用的显示方式不同这是oled屏幕。

程序框图


image.png

结果展示


image.png

直接贴代码吧这里我进行了头文件的划分,分成了小模块方便移植调用,这里只给出完整的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仿真,上文会操作的建议自己来试试,不会的可以下载工程,修改参考,时间比较紧,制作可能有些部分不太合理,欢迎大家指教

工程链接

目录
相关文章
|
6月前
|
芯片
STC15F100E单片机模拟串口
STC15F100E单片机模拟串口
STC15F100E单片机模拟串口
|
6月前
|
传感器 监控 IDE
基于单片机的温度监控系统设计
基于单片机的温度监控系统设计
239 0
|
6月前
|
物联网
STC51单片机-实验开发装置仿真-物联网应用系统设计
STC51单片机-实验开发装置仿真-物联网应用系统设计
141 0
|
6月前
|
物联网
STC51单片机-控制LED闪亮的仿真-物联网应用系统设计
STC51单片机-控制LED闪亮的仿真-物联网应用系统设计
84 0
|
内存技术
单片机(MCU)如何才能不死机之串口Overrun
单片机(MCU)如何才能不死机之串口Overrun
|
1月前
基于51单片机的proteus数字时钟仿真设计
基于51单片机的proteus数字时钟仿真设计
102 1
|
1月前
【通信协议讲解】单片机基础重点通信协议解析与总结之串口通信(三)
【通信协议讲解】单片机基础重点通信协议解析与总结之串口通信(三)
|
5月前
单片机IO口模拟串口实现原理
单片机IO口模拟串口实现原理
70 5
|
6月前
|
网络协议 Linux
嵌入式单片机开源的串口示波器实现方法
嵌入式单片机开源的串口示波器实现方法
56 0
STM32F0单片机快速入门六 用库操作串口(UART)原来如此简单
STM32F0单片机快速入门六 用库操作串口(UART)原来如此简单