本文主要是介绍TLC1543交流电压测试(单片机)教训版(千万注意电压型电路供流能力问题,注意器件属于电压输入型还是电流输入型),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
先说一下,交流电压,搞了我几个月,搞死我了,找了好几种方法转直流,进AD,就是不行。NND!!!!
在软件上仿真了好几个电路,都蛮好的波形。焊成板子就是不行,没出来电压,要么就是不滑,进了AD差天上去了,N次想砸了它GOUNIANGYANGDE!!!!!!
今天!!就在今(四声)天!!!!用的运放半波整流加RC滤波,不接入AD,调放大倍数后得到对应直流电压。接入AD后再看,MD!!!电压从珠穆朗玛都拉到贝加尔湖了!!中间串了个20K电阻(看TNND还拉低不!!)终于用表在线量OK了,程序OK了。TLC1543啊!!NNND!!!!让我一度认为运放不合适,想换其他运放,一度换电路,一度迷茫“为嘛仿真的和现实就不符昵”为嘛现实和理想差距这么大哩!!!!!一度认为仿真软件有问题!!!
所以:教训:(单片机) 教训版:
注意电路供流能力,空载和负载的电压变化受到什么影响!
注意器件属于电压输入型还是电流输入型,要“限流”,还是增大“供流”!!!
不要总是考虑电阻大影响电压,人家电流小啊!!uA级别的,TLC1543就需要限流!!!
以后再不注意这些问题!我就不姓少!!!!!!!!!!!!!
还有一个待解决问题:运放做的正弦峰值检测电路,仿真蛮好的,焊成板子就是不行,电压直接奔最高了。为嘛!!这一切都是为嘛!!运放我用的LM358,用单电池供电不行,用俩电池供电,也不行!!!
/********多周期测频法,精度与晶振和闸门时间有关。晶振越大,闸门时间越长,都可以提高精度。************************/
#include <stc89c52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define LCD12864_IO P0
#define CLERADISPLAY LCD12864_command(0x01);
int a1=0,a2=0,a3=0,a4=0,a5=0,a6=0;//存储电压值的每一位,设计a4,a5是小数位.
const uchar num[]="0123456789. ";
//AD转换控制脚
sbit CLK = P1^0; //TLC1543 18P
sbit ADDRESS = P1^1; //17P
sbit SDATA = P1^2; //16P
sbit CS = P1^3; //15P
/********************************************************************/
sbit LCD12864_RS=P2^5; // 12864-st7920 4P RS
sbit LCD12864_RW=P2^6; //RW(5P)
sbit LCD12864_EN=P2^7; //E(6P)
/********************************************************************/
void LCD12864_busy(void);
void LCD12864_command(unsigned char command);
void LCD12864_data(unsigned char dat);
void LCD12864_address(unsigned char row,unsigned char line);
void LCD12864_string(unsigned char row,unsigned char line,unsigned char *s);
void LCD12864_picture(unsigned char *gImage);
void LCD12864_init(void);
void LCD12864_char (unsigned char row,unsigned char line,unsigned char a);
unsigned char LCD12864_ReadData();
void LCD12864_Drawpoint(uchar X,uchar Y);
void LCD12864_LineX(unsigned char X0, unsigned char X1, unsigned char Y);
void LCD12864_LineY( unsigned char X, unsigned char Y0, unsigned char Y1);
void LCD12864_DrawPicture( unsigned char code *pic);
void clrgdram();
/********************************************************************/
//
double DAT[7]={1150.0, 1150.1, 1150.2, 285.0,15000.0, 4000.0,31000.0}; //都放大了10倍
// U V W E N F CINT
// 控制脚
sbit CONTRL=P1^7; //测频控制脚
sbit SCANF =P2^0; //键盘扫描控制脚
sbit LED2 =P2^1; //状态显示控制脚1
sbit LED1 =P2^2; //状态显示控制脚2
sbit SHUCHU=P2^3; //继电器输出控制脚
//
bit FLAG; //测频标志位
bit xunhuanflag;//显示方式标志位
bit outflag; //允许输出标志
bit eding;//额定状态标志
// 按键存储
bdata uchar key; //键值存储
sbit key0=key^0;//停机
sbit key1=key^1;//启动按钮
sbit key2=key^2; //显示方式(高循环)
sbit key3=key^3; //自检
sbit key4=key^4;//灯检
sbit key5=key^5;//复位
sbit key6=key^6;//应急 (高应急)
sbit key7=key^7;//油压(高有油压)
uint t1h,t1l,t2h,t2l;//测频变量
double cnt1,cnt2;
double AD; //定义为float 类型,可以防止下面做四则运算时每一步的值超出 范围
unsigned long int X;
/****************************************************************/
uint rd1543(uchar address);//AD转换程序
void voltage(); //电压检测
void init(); //初始化
void zhuansu(); //计算转速
void reset();//测频计数定时复位
uchar scanf(); //键盘扫描
void keychuli(); //按键处理程序
void baohu();
void display(unsigned long int sx,uchar j); //显示函数
void displayFX(unsigned long int sx);
/*************************************************************/
void delayus(uint);
void delayms(uint);
void delays(uint m); //延时秒
unsigned char code Bmp019[]=
{
/*------------------------------------------------------------------------------
; 若数据乱码,请检查字模格式设置,注意选择正确的取模方向和字节位顺序。
; 源文件 / 文字 : C:\Documents and Settings\Administrator\桌面\888.bmp字模
; 宽×高(像素): 128×64
; 字模格式/大小 : 单色点阵液晶字模,横向取模,字节正序/1024字节
; 数据转换日期 : 2010-7-26 20:46:48
------------------------------------------------------------------------------*/
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x01,0xF8,0x00,0x00,0x00,0x3E,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x08,0x00,0x00,0x00,0x03,0x00,0x08,0x00,0x00,0x00,0x08,0x00,0x00,0x00,
0x00,0x00,0x08,0x00,0x00,0x00,0x02,0x00,0x08,0x00,0x00,0x00,0x08,0x08,0x00,0x00,
0x00,0x20,0x18,0x00,0x00,0x00,0x08,0x00,0x1F,0x80,0x00,0x00,0x08,0x1F,0x80,0x00,
0x00,0x3D,0xF8,0x00,0x08,0x00,0x08,0xE0,0x02,0x00,0x00,0x7F,0xFF,0x00,0x80,0x00,
0x00,0x38,0x38,0x00,0x18,0x00,0x00,0x30,0x02,0x00,0x00,0x80,0x00,0x00,0x80,0x00,
0x00,0x30,0x08,0x01,0xF0,0x00,0x20,0x30,0x0F,0xF8,0x00,0x80,0x0F,0xE0,0x80,0x00,
0x00,0x30,0x38,0x00,0xFC,0x30,0x20,0xE0,0x83,0x80,0x00,0x00,0x00,0x20,0x00,0x00,
0x00,0x3F,0xF8,0x00,0x0C,0x30,0x01,0xE0,0x00,0xF0,0x00,0x02,0x00,0x20,0x00,0x00,
0x00,0x30,0x18,0x66,0xBF,0xF0,0x00,0xE0,0x0F,0xE0,0x00,0x07,0xFF,0xC0,0x00,0x00,
0x00,0x30,0x18,0x3F,0xFF,0xF0,0x00,0xC0,0x38,0x20,0x00,0x00,0x22,0x00,0x00,0x00,
0x00,0x20,0x00,0x00,0x00,0x30,0x00,0x80,0x00,0x00,0x00,0x00,0x83,0x00,0xFC,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x03,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xFF,0xFE,0x03,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xFF,0xF0,0x00,0x7F,0xFF,0xFC,0x01,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xFF,0xC3,0xF0,0x00,0x03,0xE0,0x00,0x3F,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xFF,0x8C,0x00,0x00,0x00,0x03,0xFF,0x0F,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xFE,0x00,0x03,0xFF,0xE0,0x0F,0xFF,0x87,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xFE,0x00,0xFF,0xFF,0xFE,0x1F,0xFF,0xC3,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xFE,0x03,0xFF,0xFF,0xFF,0x1F,0xFF,0xC3,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xF8,0x1F,0xFF,0xFF,0xFF,0x1F,0xFF,0xC3,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xF0,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0x87,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xE0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x07,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xC1,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x81,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0x83,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0x07,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE0,0x7F,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFE,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x3F,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFE,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF8,0x3F,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFC,0x00,0x03,0xFF,0xFF,0xFD,0x80,0x0F,0xF8,0x1F,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xF8,0x00,0x03,0xFF,0xFF,0xF8,0xFF,0x87,0xFC,0x0F,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xF8,0x03,0xFF,0xFF,0xFF,0xFF,0x00,0x1F,0xFE,0x0F,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xF8,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x0F,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xF8,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x0F,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xF8,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x0F,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xF8,0x7F,0xF0,0x0F,0xFF,0xFF,0xFF,0xFF,0xFE,0x0F,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xF8,0x3F,0xF0,0x1F,0xFF,0xFF,0xFF,0xFF,0xFC,0x0F,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xF8,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF8,0x1F,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFC,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF8,0x1F,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFE,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x3F,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFE,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE0,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0x87,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE0,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xC1,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x83,0xC0,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x07,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xFC,0x1F,0xFF,0xFF,0xFF,0xFF,0xFC,0x07,0xFF,0xC3,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xFE,0x03,0xFF,0xFF,0xFF,0xFF,0xF0,0x3F,0xFF,0xE1,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xFE,0x00,0x1F,0xFF,0xFF,0xFF,0xC3,0xFF,0xFF,0xE1,0xFF,0xFF,0xC0,
0x03,0x01,0xFF,0xF0,0x7F,0x03,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x03,0xFF,0xFF,0xC0,
0x00,0x00,0x00,0x03,0xFD,0xFF,0xFF,0xFF,0xFF,0xFE,0x00,0x3F,0xFF,0xFF,0xFF,0xC0,
0x00,0x3F,0x00,0x3F,0x80,0xFF,0xFF,0xFF,0xFF,0x10,0x1F,0xFF,0xFF,0xFF,0xFF,0xC0,
0x02,0x1F,0xFF,0xFE,0x03,0xFF,0xFF,0xFF,0xFE,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0x81,0xF8,0x00,0x03,0xFF,0xFF,0xFF,0xFE,0x03,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
//
void delayms(uint k)
{
uint data i,j;
for(i=0;i<k;i++)
{
for(j=0;j<121;j++)
{;}
}
}
//
void delayus(uint x)
{
while(--x);
}
/***********************/
void delays(uint m)
{
uint i,j;
for(i=0;i<m;i++)
{
for(i=0;i<1000;i++)
{
for(j=0;j<121;j++)
{;}
}
}
}
void Mcu_init(void)
{
LCD12864_init();
CLERADISPLAY
CLERADISPLAY
LCD12864_init();
}
/*******************************************************************/
void LCD12864_busy(void)
{
bit BF = 0;
LCD12864_EN=0;
LCD12864_RS=0;
LCD12864_RW=1;
LCD12864_IO=0xff; //单片机读数据之前必须先置高位
do
{
LCD12864_EN=1;
BF=LCD12864_IO&0x80;
LCD12864_EN=0;
} while(BF);
}
/*******************************************************************/
// 写入命令
/*******************************************************************/
void LCD12864_command(unsigned char command)
{
LCD12864_busy();
LCD12864_EN=0;
LCD12864_RS=0;
LCD12864_RW=0;
LCD12864_IO=0xff;
LCD12864_EN=1;
LCD12864_IO=command;
LCD12864_EN=0;
}
//读数据函数
unsigned char LCD12864_ReadData()
{
unsigned char read_data;
LCD12864_busy();
LCD12864_IO=0xff;
LCD12864_RS=1;
LCD12864_RW=1;
LCD12864_EN=0;
LCD12864_EN=1;
read_data=LCD12864_IO;
LCD12864_EN=0;
return(read_data);
}
/*******************************************************************/
// 写入一字节数据
/*******************************************************************/
void LCD12864_data(unsigned char dat)
{
LCD12864_busy();
LCD12864_EN=0;
LCD12864_RS=1;
LCD12864_RW=0;
LCD12864_IO=0xff;
LCD12864_EN=1;
LCD12864_IO=dat;
LCD12864_EN=0;
}
/*******************************************************************/
// 设置显示位置 row(1~4),line(1~8)
/*******************************************************************/
void LCD12864_address(unsigned char row,unsigned char line)
{
switch(row)
{
case 1:LCD12864_command(0x7f + line);
break;
case 2:LCD12864_command(0x8f + line);
break;
case 3:LCD12864_command(0x87 + line);
break;
case 4:LCD12864_command(0x97 + line);
default:
break;
}
}
/*****************显示 一个 字符 **************/
void LCD12864_char (unsigned char row,unsigned char line,unsigned char a)
{
LCD12864_address(row,line);
LCD12864_data(a);
}
/*******************************************************************/
// 在指定位置显示字符串
/*******************************************************************/
void LCD12864_string(unsigned char row,unsigned char line,unsigned char *s)
{
unsigned char LCD12864_temp;
LCD12864_address(row,line);
LCD12864_temp=*s;
while(LCD12864_temp != 0x00)
{
LCD12864_data(LCD12864_temp);
LCD12864_temp=*(++s);
}
}
/****************************
0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 上半屏行坐标,表示的是多少列
0x88 0x89 0x8a 0x8b 0x8c 0x8d 0x8e 0x8f 下半屏行坐标,每组8列,每列16位,共128位,
0x80
0x81
0x82
0x83
........
0x9f //列坐标,共32个,表示的是行数 ,分两个半屏,每个32行,共64行
//Y坐标 只是用来确定具体坐标,在哪一行
功能:图形模式下,显示(X,Y)点
输入:X(0~127) Y(0~63) 相对屏幕坐标
输出:无
点亮某一点的操作步骤: 1.求出水平坐标X对应的地址和是哪一位 0x80-----0x8f (范围0-15) X/16求地址 X%16求该地址哪一位
2.求垂直坐标Y对应的地址和上下半屏 0x80------0x9f(范围0-63) Y本身就是8位地址,Y=63-Y ,Y--(0-31)
3.写入行列地址(Y是行X是列),0x80+Y ,0X80+X/16
4.读要显示的数据 DAT
5.区分上下半屏(X%16<=7&&X%16>=0是上半屏)写入数据每一位 DAT|0x80 ;DAT<<1
注意:这个函数显示某一点时,可能会把上次显示的处于同一地址的其他位的点擦掉,所以先保存所有数据,最后显示,就连贯起来了
*******************************/
/*******************************************************************/
/**************************************************************/
//------------------清整个GDRAM空间----------------------------
/**************************************************************/
void clrgdram()
{
unsigned char x,y ;
for(y=0;y<64;y++)
for(x=0;x<16;x++)
{
LCD12864_command(0x34);
LCD12864_command(y+0x80);
LCD12864_command(x+0x80);
LCD12864_command(0x30);
LCD12864_data(0x00);
LCD12864_data(0x00);
}
}
/******************************************/
/*******8==========================================================================
功能:图形模式下,显示(X,Y)点
输入:X(0~127) Y(0~63)
输出:无
0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 上半屏行坐标,表示的是多少列,X地址
0x88 0x89 0x8a 0x8b 0x8c 0x8d 0x8e 0x8f 下半屏行坐标,X地址 (水平地址 )
0x80 (垂直地址)
0x81
0x82
0x83
........
0x9f //列坐标,共32个,表示的是行数 ,分两个半屏,每个32行,共64行
====================================================================**********/
void LCD12864_Drawpoint(uchar X,uchar Y)
{
uchar i= 0, j = 0,ok=0;
uchar temp1 = 0x00,temp2 = 0x00;
LCD12864_command(0x34); //8位,扩充指令,绘图关
LCD12864_command(0x36); //8位,扩充指令,绘图开
i = X/16; //计算出X字节地址(0X80-0X8F)
j = X%16; //计算出该字节的具体位(0-15)
//Y = 63 - Y;
if(Y>=0 && Y<=31)//判断上下半屏
{
ok=1;
}
else if(Y>=32 && Y<=63)//下半屏
{
Y = Y - 32;//Y只有0-31共32个 地址
i = i + 8;//X地址进入下半屏 (0X88-0X8F)
ok=1;
}
if(ok)
{
//读数据操作
LCD12864_command(0x80+Y); //第一步:设置Y坐标,读数据先写地址,写GDRAM时先写垂直地址(0X80-0X9F)
LCD12864_command(0x80+i); //第二步:设置X坐标
LCD12864_ReadData(); //第三步:空读取一次
temp1 =LCD12864_ReadData(); //第四步:读取高字节,先读高字节
temp2 =LCD12864_ReadData(); //第五步:读取低字节
//图形模式下的写数据操作
LCD12864_command(0x80+Y); //第一步:设置Y坐标
LCD12864_command(0x80+i); //第二步:设置X坐标
if(j>=0 && j<=7) //判断是高字节
{
LCD12864_data(temp1|(0x80>>j)); //第三步:写高字节数据
LCD12864_data(temp2); //第四步:写低字节数据
}
else if(j>7 && j<=15) //判断是低字节
{
j = j - 8;
LCD12864_data(temp1);
LCD12864_data(temp2|(0x80>>j)); //改变字节里的位
}
}
}
/******************************************/
//画线
/********************************************/
//画水平线
void LCD12864_LineX(unsigned char X0, unsigned char X1, unsigned char Y)
{
unsigned char Temp ;
if( X0 > X1 )
{
Temp = X1 ; //交换X0 X1值
X1 = X0 ; //大数存入X1
X0 = Temp; //小数存入X0
}
for( ; X0 <= X1 ; X0++ )
LCD12864_Drawpoint(X0,Y);
}
//画垂直线
void LCD12864_LineY( unsigned char X, unsigned char Y0, unsigned char Y1)
{
unsigned char Temp ;
if( Y0 > Y1 )//交换大小值
{
Temp = Y1 ;
Y1 = Y0 ;
Y0 = Temp ;
}
for(; Y0 <= Y1 ; Y0++)
LCD12864_Drawpoint( X, Y0) ;
}
/******************************************/
/**************画图************************/
void LCD12864_DrawPicture( unsigned char code *pic)
{
unsigned char i, j, k ;
LCD12864_command(0x34);//开扩充指令
LCD12864_command(0x36);//开绘图功能
for( i = 0 ; i < 2 ; i++ )//分上下两屏写
{
for( j = 0 ; j < 32 ; j++)//垂直地址递加 ,行扫方式
{
LCD12864_command( 0x80 + j ) ;//写Y坐标(Y的范围: 0X80-0X9F )
if( i == 0 ) //写X坐标
{
LCD12864_command(0x80);//上半屏
}
else
{
LCD12864_command(0x88);//下半屏开始地址
}
for( k = 0 ; k < 16 ; k++ ) //写一整行数据
{
LCD12864_data( *pic++ );//前面只写入首地址,后面依次写入数据,地址会自动递增
}
}
}
LCD12864_command( 0x30);//恢复到一般模式
}
// 初始化设置
/*******************************************************************/
void LCD12864_init(void)
{
CLERADISPLAY // clear DDRAM
LCD12864_command(0x30); // 8 bits unsigned interface,basic instrument
LCD12864_command(0x02); // cursor return
LCD12864_command(0x0c); // display,cursor on
LCD12864_command(0x03);
LCD12864_command(0x06);
CLERADISPLAY // clear DDRAM
}
//
//显示函数
void display(unsigned long int sx,uchar j)
{
a1=sx/100000;
a2=sx%100000/10000;
a3=sx%10000/1000;//千位
a4=sx%1000/100;//百位
a5=sx%100/10;//十位
a6=sx%10;//个位
switch(j)
{
case 0x00: LCD12864_string(2,5," Ua ");break;
case 0x01: LCD12864_string(2,5," Ub ");break;
case 0x02: LCD12864_string(2,5," Uc ");break;
case 0x03: LCD12864_string(2,5," E ");break;
case 0x04: LCD12864_string(2,5," 转速 ");break;
case 0x05: LCD12864_string(2,5," 频率 ");break;
case 0x06: LCD12864_string(2,5,"脉冲计数");break;
case 0x07: LCD12864_string(2,5," ");break;
default :break;
}
LCD12864_command(0x90); //指定显示位置
LCD12864_data(num[a1]); //从最高位开始显示
LCD12864_data(num[a2]);
LCD12864_data(num[a3]);
LCD12864_data(num[a4]);
LCD12864_data(num[a5]);
LCD12864_data(num[10]);//小数点,前面测量计算时扩大了10倍,这里缩小回来
LCD12864_data(num[a6]);
}
/*********************************
主函数入口
/********************************************/
//主函数入口
//
main()
{
uchar ii=0;
CONTRL=0;
FLAG=0;
P0=0x00;
LED1=0;
LED1=1;
P0=0x00;
LED2=0;
LED2=1;
P0=0x00;
SHUCHU=0;//打开闸门
SHUCHU=1;
baohu();//判断采样数据保护
Mcu_init();
CLERADISPLAY
delays(1);
display(100000,7);
LCD12864_char(1,2,'A');
LCD12864_string(1,2,"shaozhanyu");
delays(2);
clrgdram();
CLERADISPLAY
delays(1);
clrgdram();
delays(1);
LCD12864_LineX(8,113,25);
clrgdram();
CLERADISPLAY
delays(2);
clrgdram();
LCD12864_LineY(55,29,57);
delays(2);
clrgdram();
delays(1);
LCD12864_DrawPicture(Bmp019);
delays(3);
Mcu_init();
CLERADISPLAY
LCD12864_string(3,1,"U V W E SP F CT");
LCD12864_char(2,1,'D');
LCD12864_string(4,1,"计数");
LCD12864_string(1,2,"少占鱼做");
delays(1);
/***************8888
P0=0x10;//怠速,准备打开K5继电器,关闭其他输出继电器
SHUCHU=0;//打开输出闸门
SHUCHU=1;//关闭闸门
outflag=0;//输出标志位
******************/
AD=0.0;
LCD12864_string(1,2,"灯光测试");
P0=0x41;
LED1=0;
LED1=1;
delayms(1000);
P0=0x42;
LED1=0;
LED1=1;
delayms(1000);
P0=0x44;
LED1=0;
LED1=1;
delayms(1000);
P0=0x48;
LED1=0;
LED1=1;
delayms(1000);
P0=0x50;
LED1=0;
LED1=1;
delayms(1000);
P0=0x60;
LED1=0;
LED1=1;
delayms(1000);
P0=0x41;
LED2=0;
LED2=1;
delayms(1000);
P0=0x42;
LED2=0;
LED2=1;
delayms(1000);
P0=0x44;
LED2=0;
LED2=1;
delayms(1000);
P0=0x48;
LED2=0;
LED2=1;
delayms(1000);
P0=0x50;
LED2=0;
LED2=1;
delayms(1000);
P0=0x60;
LED2=0;
LED2=1;
delayms(1000);
P0=0x00;
LED1=0;
LED1=1;
P0=0x00;
LED2=0;
LED2=1;
delayms(500);
LCD12864_string(1,2,"测继电器");
P0=0x04;//启动
SHUCHU=0;//打开闸门
delays(3);
SHUCHU=1;
P0=0x18;//停机
SHUCHU=0;//打开闸门
delays(3);
SHUCHU=1;
P0=0x40;//怠速,准备打开K5继电器,关闭其他输出继电器
SHUCHU=0;//打开输出闸门
delays(3);
SHUCHU=1;//关闭闸门
P0=0xa0;//准备合闸(交流,直流 内控制 )
SHUCHU=0;
delays(3);
SHUCHU=1;
P0=0x00;
SHUCHU=0;//打开闸门
SHUCHU=1;
keychuli(); //扫描并处理按键
delayms(600);
voltage();
LCD12864_string(3,1,"U V W E SP F ");
LCD12864_char(2,1,'D');
LCD12864_string(1,2,"少氏出品");
delays(11);
///初始化
LCD12864_string(4,1,"直流正常");
init();
while(1)
{
while(!FLAG); //等待频率测出
keychuli(); //扫描并处理按键
LCD12864_string(1,2,"测量电压");
delayms(500);
voltage(); //采样电压
LCD12864_string(1,2,"转换完成");
delayms(600);
baohu();//判断采样数据保护
for(;ii<6;)
{
if(xunhuanflag==0) //定点
{display(DAT[ii],ii);
LCD12864_string(1,2,"定点显示");
break;
}
display(DAT[ii],ii);
LCD12864_string(1,2,"循环显示");
delayms(2200);
keychuli();
ii++;
}//循环 显示结束
if(ii==6)
ii=0;
LCD12864_string(1,2,"下轮复位");
delayms(700);
init();
}
}
/*************************************/
//初始化函数
void init()
{
/******T1定时器模式,外部INT1控制开启,T0计数器不允许中断,外部控制
INTO开启,外部中断0允许(EX0=1),
定时器T2中断允许 (ET2=1) ************/
CONTRL=0;
FLAG=0;
EX0=0;
ET2=0;
//三个定时器方式设置
TMOD=0x9d; //T0T1方式控制
T2MOD=0x00;
T2CON=0x00;//定时器2,16位定时方式,自动重装。
TH0= 0x00; // T0高8位
TL0= 0x00; // T0低8位
TH1= 0x00; // T1高8位
TL1= 0x00; // T1低8位
EXEN2=0;
TH2=256/256;
TL2=256%256;
RCAP2H=256/256;
RCAP2L=256%256;
//中断设置 5
EX0=1;//允许外部0输入中断(INT0引脚)
ET2=1; //开定时中断2
IT0=1; //外部中断0边沿触发,下降沿到来触发
//优先级设置
PX0=1;
//预置T0,T1
TR1=1;//先允许T1定时,因T1的GATE=1,还要等外部INT1高电平才计数
TR0=1;//先允许T0计数 ,同T1一样,等待INTO高电平
TR2=1;//启动T2定时,不用外部控制,直接启动
EA=1; //开全局中断
CONTRL=1;
//初始化完成......
}
/**********************************
void reset()
{
CONTRL=0;
FLAG=0;
TL0=0x00;
TH0=0x00;
TL1=0x00;
TH1=0x00;
TF2=0;
TH2=256/256;
TL2=256%256;
TR1=1;//先允许T1定时,因T1的GATE=1,还要等外部INT1高电平才计数
TR0=1;//先允许T0计数 ,同T1一样,等待INTO高电平
TR2=1;//启动T2定时,不用外部控制,直接启动
EA=1; //开全局中断
CONTRL=1;
}
*******************************/
//键盘扫描
uchar scanf()
{
uchar value;
P0=0xff;
delayms(1);
SCANF=0;//打开键扫闸门
value=P0;
delayms(2);
value=P0;
SCANF=1;
return value;
}
/********************************/
//键处理
void keychuli()
{
uchar k;
//关于指示灯,交流是一组,直流是一组,其他状态用液晶显示
/***************************************/
/******************/
key=scanf();
/******************/
//启动键判断
if(key1==0&&key7==0&&DAT[4]==0)//启动位 ,油压和转速为0
{
for(k=0;k<3;k++)//三次启动循环
{
P0=0x04;//准备 输出K6继电器
SHUCHU=0;//打开闸门
delays(3);//隔三秒响应一次停机键
//响应停机键
key=scanf();
if(key0==0&&key7==1&&DAT[4]>500)//停机开关状态,油压高,转速达到500,其他继电器都停止工作 ,所以 ,P0=0x08
{
P0=0x18;//准备输出K0,K9继电器
SHUCHU=0;//打开输出闸门
SHUCHU=1;//关闭闸门
outflag=0;//输出标志位
}
if(key1==0&&key7==1&&DAT[4]>430) //每启动一次都判断是否成功,成功直接跳出
break ; //判断启动成功,立即跳出启动for 循环
delays(3);//没有启动成功,继续启动3秒
key=scanf();
if(key1==0&&key0==0&&key7==1&&DAT[4]>500)//停机,油压高,转速达到500,其他继电器都停止工作 ,所以 ,P0=0x08
{
P0=0x18;//准备输出K0,K9继电器
SHUCHU=0;//打开输出闸门
SHUCHU=1;//关闭闸门
outflag=0;//输出标志位
}
if(key1==0&&key7==1&&DAT[4]>430) //每启动一次都判断是否成功,成功直接跳出
break ;
delays(3);
key=scanf();
if(key0==0&&key7==1&&DAT[4]>500)//停机,油压高,转速达到500,其他继电器都停止工作 ,所以 ,P0=0x08
{
P0=0x18;//准备输出K0,K9继电器
SHUCHU=0;//打开输出闸门
SHUCHU=1;//关闭闸门
outflag=0;//输出标志位
}
if(key1==0&&key7==1&&DAT[4]>430) //每启动一次都判断是否成功,成功直接跳出
break ;
P0=0x18;//停止
SHUCHU=0;
SHUCHU=1;
delays(9);
}//for启动循环结束
SHUCHU=1;//关闭闸门
/**********************/
//启动失败判断
if(key7==0) //油压低
if(DAT[4]<440)
{
P0=0x01;//点亮启动失败灯
LED1=0;//开启573输入
LED1=1;//关闭使能,74HC573锁定状态
outflag=0;//输出标志位清0,表示输出未允许
}
}
//停机键判断
/********************/
if(key0==0&&key7==1&&DAT[4]>500)//停机,油压高,转速达到500,其他继电器都停止工作 ,所以 ,P0=0x08
{
P0=0x00;//准备交直流断闸(交流,直流 内控制 )
SHUCHU=0;
SHUCHU=1;
delayms(3);
P0=0x40;//怠速,准备打开K5继电器,关闭其他输出继电器
SHUCHU=0;//打开输出闸门
SHUCHU=1;//关闭闸门
outflag=0;
delays(29);
P0=0x18;//准备 输出K0和K9停油继电器
SHUCHU=0;//打开输出闸门
SHUCHU=1;//关闭闸门
outflag=0;//输出标志位
}
/*****************/
//应急键判断
if(key6==1)//应急/正常,高电位应急
{
eding=1;//应急标志
}
else if(key6==0) //进入怠速
{
eding=0;//怠速标志
}
if(eding==0)//对怠速的处理
{
P0=0x40;//怠速,准备打开K5继电器,关闭其他输出继电器
SHUCHU=0;//
SHUCHU=1;//关闭闸门
outflag=0;
}
if(eding==1&&outflag==0)//对额定的处理
{
P0=0x00;//额定,准备关闭K5继电器,进入额定,其他继电器都停止工作 ,所以 ,P0=0x00
SHUCHU=0;//打开输出闸门
SHUCHU=1;//关闭闸门
delayms(2);
if(DAT[0]>110&&DAT[1]>110&&DAT[2]>110&&DAT[5]>390)//三相交流大于110 ,频率大于390
{
P0=0xa0;//准备合闸(交流,直流 内控制 )
SHUCHU=0;
SHUCHU=1;
outflag=1;//合闸后,输出标志位置1
}
}
/******************************/
//循环键
if(key2==1) //处理循环定点显示标志位
xunhuanflag=1;
else if(key2==0)
xunhuanflag=0;
/*********************/
//灯光检查键
if(key4==0)//灯光检查
{
LED1=1;
LED2=1;
P0=0x7f;
LED1=0;
delayus(10);
LED1=1;
delayms(1000);
P0=0x7f;
LED2=0;
delayus(10);
LED2=1;
}
/************************/
//复位键
if(key5==0)//复位
{
P0=0x00;
LED1=0;
delayus(10);
LED1=1;
P0=0x00;
LED2=0;
delayus(10);
LED2=1;
}
/****************/
//自检键
if(key3==0) //自检
{ }
}
/**********保护函数*****************/
void baohu()
{
if(outflag==1)//前提是已经输出
{
//立即保护值
if((DAT[0]<800||DAT[1]<800||DAT[2]<800) || (DAT[0]>1800||DAT[1]>1800||DAT[2]>1800) || DAT[5]>4450||DAT[5]<3200)//立即断闸保护
{
P0=0x00;//准备断闸(交流,直流 内控制 )
SHUCHU=0;
SHUCHU=1;
outflag=0;//断闸后,输出标志位清0
if(DAT[0]>1800||DAT[1]>1800||DAT[2]>1800)
{
P0=0x80;//过压
LED1=0;
LED1=1;
}
if(DAT[5]>4450)
{
P0=0x80;//过频灯
LED2=0;
LED2=1;
}
if(DAT[0]<800||DAT[1]<800||DAT[2]<800)
{
P0=0x40;//欠压
LED1=0;
LED1=1;
}
if(DAT[5]<3200)
{
P0=0x40;//欠频灯
LED2=0;
LED2=1;
}
}//立即保护结束
// 延时保护值
if(DAT[0]<1000||DAT[1]<1000||DAT[2]<1000|| DAT[0]>1270||DAT[1]>1270||DAT[2]>1270|| DAT[5]>4300||DAT[5]<3700)
{
if(DAT[0]>1270||DAT[1]>1270||DAT[2]>1270)
{
P0=0x80;//过压
LED1=0;
LED1=1;
}
if(DAT[5]>4300)
{
P0=0x80;//过频
LED2=0;
LED2=1;
}
if(DAT[0]<1000||DAT[1]<1000||DAT[2]<1000)
{
P0=0x40;//欠压
LED1=0;
LED1=1;
}
if(DAT[5]<3700)
{
P0=0x40;//欠频
LED2=0;
LED2=1;
}
delays(4);//等待交流恢复
voltage();
if(DAT[0]>1100&&DAT[1]>1100&&DAT[2]>1100&&DAT[5]>3900)//三相交流大于110 ,频率大于390
{
P0=0x00;
LED1=0;
LED1=1;
P0=0x00;
LED2=0;
LED2=1;
P0=0xa0;//准备合闸(交流直流内控制 )
SHUCHU=0;
SHUCHU=1;
outflag=1;//合闸后,输出标志位置1
}
else
{
P0=0x00;//准备断闸(交流,直流 内控制 )
SHUCHU=0;
SHUCHU=1;
outflag=0;
}
}//交流和频率保护结束
//直流电压延时保护
if(DAT[3]>320||DAT[3]<170)
{if(DAT[3]>320)
{
LCD12864_string(4,1,"直流过压");
}
delays(4);//等待直流过压恢复
voltage();
if(DAT[3]>170&&DAT[3]<320)
{
LCD12864_string(4,1,"直流正常");
}
else
{P0=0x80;//关闭直流只开交流,因为前面已经检测过交流了,这里就不管了,当他正常
SHUCHU=0;
SHUCHU=1;
outflag=1;
LCD12864_string(4,1,"直流故障");
}
if(DAT[3]<170)
{
LCD12864_string(4,1,"直流欠压");
}
delays(2);//等待直流 欠压恢复
voltage();
if(DAT[3]>170&&DAT[3]<320)
{
LCD12864_string(4,1,"直流正常");
}
else
{P0=0x80;//关闭直流只开交流,因为前面已经检测过交流了,这里就不管了,当他正常
SHUCHU=0;
SHUCHU=1;
outflag=1;
LCD12864_string(4,1,"直流故障");
}
}//直流延时保护结束
}//总 保护结束
}//总函数结束
/*******************************/
//转速计算 ,频率计算
void zhuansu()
{
t1h=TH0;
t1l=TL0;
t2h=TH1;
t2l=TL1;
cnt1=t1l+(t1h<<8);
cnt2=t2l+(t2h<<8);
DAT[6]=cnt1/cnt2*1000000.20*10.00;//计数值
DAT[4]=cnt1/cnt2*1000000.200/124.00*600.00*10.0; //计算转速,信号频率就是单片机计数频率的整数倍 ,这里这样写是怕cnt1 cnt2 超出范围
//注意这里: cnt1 cnt2 的类型不能是 uint 否则第一步计算除法会得0 , 如果你要先乘1000000.0,也不行。因为超出了uint 范围
DAT[5]=DAT[4]*16.00/60.000*10.0;//电压频率计算
}
/******************************/
//外部中断0,调用转速计算
void interint0() interrupt 0 //using **
//外部中断0处理
{
EA=0;
zhuansu();//调用转速函数
FLAG=1;
/***注意:因为TO T1是外部引脚控制的,所以,这时外部低电平,自动停止。不用软件停止**/
}
void intertimer2() interrupt 5 //using **
//T2定时中断处理
{
TR2=0;
CONTRL=0;//关闭闸门信号
}
/*******************************/
//AD转换程序
/************************************************/
//常测数据函数
void voltage() //电压测量
{
uchar i;
AD=0.00;
X=0;
for(i=0;i<10;i++)
{
AD+=rd1543(0x08); //读取AD值
}
//
AD=AD/10.0;
X=AD*46.0001*50.00/1023.00;//转换成电压值 ,分辨率是10位
DAT[0]=X;
AD=0.00;
//
for(i=0;i<10;i++)
{
AD+=rd1543(0x08); //读取AD值
}
//
AD=AD/10.0;
X=AD*46.0001*50.00/1023.00;//转换成电压值 ,分辨率是10位
DAT[1]=X;
//
AD=0.00;
//
for(i=0;i<10;i++)
{
AD+=rd1543(0x08); //读取AD值
}
//
AD=AD/10.0;
X=AD*46.0001*50.00/1023.00;//转换成电压值 ,分辨率是10位
DAT[2]=X;
//
/*********
for(i=0;i<20;i++)
{
AD+=rd1543(0x07); //读取AD值
}
//
AD=AD/20;
X=AD*50.000/1023.000*28.500/4.000;
DAT[3]=X;
//
**********/
}
/***********************************************/
//TLC1543输入模拟电压范围: 0-4.9152 V
//TLC1543AD 10个时钟方式 方式1 。 LC1543 有四位精度 。 输入 0.0024v 时,AD值为0000000001
//0.0048时,还为1。 0.0072为 2 也就是0.0048 为一个 宽度 0.0048*AD 就是电压值 .
uint rd1543(uchar addr)
{
uint date_out=0;
uchar k;
// uchar j;
CLK=0;
CS=0;
ADDRESS=(bit)(addr&0x08); //用这种愚蠢的方法比用FOR循环快的多 。
CLK=1;
CLK=0;
addr=addr*2; //用乘法比用左移快
ADDRESS=(bit)(addr&0x08);
CLK=1;
CLK=0;
addr=addr*2; //用乘法比用左移快
ADDRESS=(bit)(addr&0x08);
CLK=1;
CLK=0;
addr=addr*2; //用乘法比用左移快
ADDRESS=(bit)(addr&0x08);
CLK=1;
CLK=0;
addr=addr*2; //用乘法比用左移快
// for (j=0;j<6;j++) //填充6 个CLOCK
// {
CLK=1;CLK=0; //这里不用循环,省时间
CLK=1;CLK=0;
CLK=1;CLK=0;
CLK=1;CLK=0;
CLK=1;CLK=0;
CLK=1;CLK=0;
CLK=0;
// }
CS=1;
delayus(8); //等待AD 转换
CS=0;
for(k=0;k<10;k++)
{
SDATA=1; //非P0口作为数据总线使用时,读入数据前要赋值1,特别
CLK = 1; //是既用于写有用于读的情况下.
date_out<<=1;
if(SDATA) date_out += 1; //这样写法比下面的方法速度快(5us)
// date_out=date_out|SDATA;//用时6US
CLK = 0;
}
return(date_out);
}
在软件上仿真了好几个电路,都蛮好的波形。焊成板子就是不行,没出来电压,要么就是不滑,进了AD差天上去了,N次想砸了它GOUNIANGYANGDE!!!!!!
今天!!就在今(四声)天!!!!用的运放半波整流加RC滤波,不接入AD,调放大倍数后得到对应直流电压。接入AD后再看,MD!!!电压从珠穆朗玛都拉到贝加尔湖了!!中间串了个20K电阻(看TNND还拉低不!!)终于用表在线量OK了,程序OK了。TLC1543啊!!NNND!!!!让我一度认为运放不合适,想换其他运放,一度换电路,一度迷茫“为嘛仿真的和现实就不符昵”为嘛现实和理想差距这么大哩!!!!!一度认为仿真软件有问题!!!
所以:教训:(单片机) 教训版:
注意电路供流能力,空载和负载的电压变化受到什么影响!
注意器件属于电压输入型还是电流输入型,要“限流”,还是增大“供流”!!!
不要总是考虑电阻大影响电压,人家电流小啊!!uA级别的,TLC1543就需要限流!!!
以后再不注意这些问题!我就不姓少!!!!!!!!!!!!!
还有一个待解决问题:运放做的正弦峰值检测电路,仿真蛮好的,焊成板子就是不行,电压直接奔最高了。为嘛!!这一切都是为嘛!!运放我用的LM358,用单电池供电不行,用俩电池供电,也不行!!!
/********多周期测频法,精度与晶振和闸门时间有关。晶振越大,闸门时间越长,都可以提高精度。************************/
#include <stc89c52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define LCD12864_IO P0
#define CLERADISPLAY LCD12864_command(0x01);
int a1=0,a2=0,a3=0,a4=0,a5=0,a6=0;//存储电压值的每一位,设计a4,a5是小数位.
const uchar num[]="0123456789. ";
//AD转换控制脚
sbit CLK = P1^0; //TLC1543 18P
sbit ADDRESS = P1^1; //17P
sbit SDATA = P1^2; //16P
sbit CS = P1^3; //15P
/********************************************************************/
sbit LCD12864_RS=P2^5; // 12864-st7920 4P RS
sbit LCD12864_RW=P2^6; //RW(5P)
sbit LCD12864_EN=P2^7; //E(6P)
/********************************************************************/
void LCD12864_busy(void);
void LCD12864_command(unsigned char command);
void LCD12864_data(unsigned char dat);
void LCD12864_address(unsigned char row,unsigned char line);
void LCD12864_string(unsigned char row,unsigned char line,unsigned char *s);
void LCD12864_picture(unsigned char *gImage);
void LCD12864_init(void);
void LCD12864_char (unsigned char row,unsigned char line,unsigned char a);
unsigned char LCD12864_ReadData();
void LCD12864_Drawpoint(uchar X,uchar Y);
void LCD12864_LineX(unsigned char X0, unsigned char X1, unsigned char Y);
void LCD12864_LineY( unsigned char X, unsigned char Y0, unsigned char Y1);
void LCD12864_DrawPicture( unsigned char code *pic);
void clrgdram();
/********************************************************************/
//
double DAT[7]={1150.0, 1150.1, 1150.2, 285.0,15000.0, 4000.0,31000.0}; //都放大了10倍
// U V W E N F CINT
// 控制脚
sbit CONTRL=P1^7; //测频控制脚
sbit SCANF =P2^0; //键盘扫描控制脚
sbit LED2 =P2^1; //状态显示控制脚1
sbit LED1 =P2^2; //状态显示控制脚2
sbit SHUCHU=P2^3; //继电器输出控制脚
//
bit FLAG; //测频标志位
bit xunhuanflag;//显示方式标志位
bit outflag; //允许输出标志
bit eding;//额定状态标志
// 按键存储
bdata uchar key; //键值存储
sbit key0=key^0;//停机
sbit key1=key^1;//启动按钮
sbit key2=key^2; //显示方式(高循环)
sbit key3=key^3; //自检
sbit key4=key^4;//灯检
sbit key5=key^5;//复位
sbit key6=key^6;//应急 (高应急)
sbit key7=key^7;//油压(高有油压)
uint t1h,t1l,t2h,t2l;//测频变量
double cnt1,cnt2;
double AD; //定义为float 类型,可以防止下面做四则运算时每一步的值超出 范围
unsigned long int X;
/****************************************************************/
uint rd1543(uchar address);//AD转换程序
void voltage(); //电压检测
void init(); //初始化
void zhuansu(); //计算转速
void reset();//测频计数定时复位
uchar scanf(); //键盘扫描
void keychuli(); //按键处理程序
void baohu();
void display(unsigned long int sx,uchar j); //显示函数
void displayFX(unsigned long int sx);
/*************************************************************/
void delayus(uint);
void delayms(uint);
void delays(uint m); //延时秒
unsigned char code Bmp019[]=
{
/*------------------------------------------------------------------------------
; 若数据乱码,请检查字模格式设置,注意选择正确的取模方向和字节位顺序。
; 源文件 / 文字 : C:\Documents and Settings\Administrator\桌面\888.bmp字模
; 宽×高(像素): 128×64
; 字模格式/大小 : 单色点阵液晶字模,横向取模,字节正序/1024字节
; 数据转换日期 : 2010-7-26 20:46:48
------------------------------------------------------------------------------*/
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x01,0xF8,0x00,0x00,0x00,0x3E,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x08,0x00,0x00,0x00,0x03,0x00,0x08,0x00,0x00,0x00,0x08,0x00,0x00,0x00,
0x00,0x00,0x08,0x00,0x00,0x00,0x02,0x00,0x08,0x00,0x00,0x00,0x08,0x08,0x00,0x00,
0x00,0x20,0x18,0x00,0x00,0x00,0x08,0x00,0x1F,0x80,0x00,0x00,0x08,0x1F,0x80,0x00,
0x00,0x3D,0xF8,0x00,0x08,0x00,0x08,0xE0,0x02,0x00,0x00,0x7F,0xFF,0x00,0x80,0x00,
0x00,0x38,0x38,0x00,0x18,0x00,0x00,0x30,0x02,0x00,0x00,0x80,0x00,0x00,0x80,0x00,
0x00,0x30,0x08,0x01,0xF0,0x00,0x20,0x30,0x0F,0xF8,0x00,0x80,0x0F,0xE0,0x80,0x00,
0x00,0x30,0x38,0x00,0xFC,0x30,0x20,0xE0,0x83,0x80,0x00,0x00,0x00,0x20,0x00,0x00,
0x00,0x3F,0xF8,0x00,0x0C,0x30,0x01,0xE0,0x00,0xF0,0x00,0x02,0x00,0x20,0x00,0x00,
0x00,0x30,0x18,0x66,0xBF,0xF0,0x00,0xE0,0x0F,0xE0,0x00,0x07,0xFF,0xC0,0x00,0x00,
0x00,0x30,0x18,0x3F,0xFF,0xF0,0x00,0xC0,0x38,0x20,0x00,0x00,0x22,0x00,0x00,0x00,
0x00,0x20,0x00,0x00,0x00,0x30,0x00,0x80,0x00,0x00,0x00,0x00,0x83,0x00,0xFC,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x03,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xFF,0xFE,0x03,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xFF,0xF0,0x00,0x7F,0xFF,0xFC,0x01,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xFF,0xC3,0xF0,0x00,0x03,0xE0,0x00,0x3F,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xFF,0x8C,0x00,0x00,0x00,0x03,0xFF,0x0F,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xFE,0x00,0x03,0xFF,0xE0,0x0F,0xFF,0x87,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xFE,0x00,0xFF,0xFF,0xFE,0x1F,0xFF,0xC3,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xFE,0x03,0xFF,0xFF,0xFF,0x1F,0xFF,0xC3,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xF8,0x1F,0xFF,0xFF,0xFF,0x1F,0xFF,0xC3,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xF0,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0x87,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xE0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x07,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xC1,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x81,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0x83,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0x07,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE0,0x7F,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFE,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x3F,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFE,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF8,0x3F,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFC,0x00,0x03,0xFF,0xFF,0xFD,0x80,0x0F,0xF8,0x1F,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xF8,0x00,0x03,0xFF,0xFF,0xF8,0xFF,0x87,0xFC,0x0F,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xF8,0x03,0xFF,0xFF,0xFF,0xFF,0x00,0x1F,0xFE,0x0F,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xF8,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x0F,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xF8,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x0F,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xF8,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x0F,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xF8,0x7F,0xF0,0x0F,0xFF,0xFF,0xFF,0xFF,0xFE,0x0F,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xF8,0x3F,0xF0,0x1F,0xFF,0xFF,0xFF,0xFF,0xFC,0x0F,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xF8,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF8,0x1F,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFC,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF8,0x1F,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFE,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x3F,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFE,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE0,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0x87,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE0,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xC1,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x83,0xC0,0xFF,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x07,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xFC,0x1F,0xFF,0xFF,0xFF,0xFF,0xFC,0x07,0xFF,0xC3,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xFE,0x03,0xFF,0xFF,0xFF,0xFF,0xF0,0x3F,0xFF,0xE1,0xFF,0xFF,0xC0,
0x03,0xFF,0xFF,0xFE,0x00,0x1F,0xFF,0xFF,0xFF,0xC3,0xFF,0xFF,0xE1,0xFF,0xFF,0xC0,
0x03,0x01,0xFF,0xF0,0x7F,0x03,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x03,0xFF,0xFF,0xC0,
0x00,0x00,0x00,0x03,0xFD,0xFF,0xFF,0xFF,0xFF,0xFE,0x00,0x3F,0xFF,0xFF,0xFF,0xC0,
0x00,0x3F,0x00,0x3F,0x80,0xFF,0xFF,0xFF,0xFF,0x10,0x1F,0xFF,0xFF,0xFF,0xFF,0xC0,
0x02,0x1F,0xFF,0xFE,0x03,0xFF,0xFF,0xFF,0xFE,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,
0x03,0x81,0xF8,0x00,0x03,0xFF,0xFF,0xFF,0xFE,0x03,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
//
void delayms(uint k)
{
uint data i,j;
for(i=0;i<k;i++)
{
for(j=0;j<121;j++)
{;}
}
}
//
void delayus(uint x)
{
while(--x);
}
/***********************/
void delays(uint m)
{
uint i,j;
for(i=0;i<m;i++)
{
for(i=0;i<1000;i++)
{
for(j=0;j<121;j++)
{;}
}
}
}
void Mcu_init(void)
{
LCD12864_init();
CLERADISPLAY
CLERADISPLAY
LCD12864_init();
}
/*******************************************************************/
void LCD12864_busy(void)
{
bit BF = 0;
LCD12864_EN=0;
LCD12864_RS=0;
LCD12864_RW=1;
LCD12864_IO=0xff; //单片机读数据之前必须先置高位
do
{
LCD12864_EN=1;
BF=LCD12864_IO&0x80;
LCD12864_EN=0;
} while(BF);
}
/*******************************************************************/
// 写入命令
/*******************************************************************/
void LCD12864_command(unsigned char command)
{
LCD12864_busy();
LCD12864_EN=0;
LCD12864_RS=0;
LCD12864_RW=0;
LCD12864_IO=0xff;
LCD12864_EN=1;
LCD12864_IO=command;
LCD12864_EN=0;
}
//读数据函数
unsigned char LCD12864_ReadData()
{
unsigned char read_data;
LCD12864_busy();
LCD12864_IO=0xff;
LCD12864_RS=1;
LCD12864_RW=1;
LCD12864_EN=0;
LCD12864_EN=1;
read_data=LCD12864_IO;
LCD12864_EN=0;
return(read_data);
}
/*******************************************************************/
// 写入一字节数据
/*******************************************************************/
void LCD12864_data(unsigned char dat)
{
LCD12864_busy();
LCD12864_EN=0;
LCD12864_RS=1;
LCD12864_RW=0;
LCD12864_IO=0xff;
LCD12864_EN=1;
LCD12864_IO=dat;
LCD12864_EN=0;
}
/*******************************************************************/
// 设置显示位置 row(1~4),line(1~8)
/*******************************************************************/
void LCD12864_address(unsigned char row,unsigned char line)
{
switch(row)
{
case 1:LCD12864_command(0x7f + line);
break;
case 2:LCD12864_command(0x8f + line);
break;
case 3:LCD12864_command(0x87 + line);
break;
case 4:LCD12864_command(0x97 + line);
default:
break;
}
}
/*****************显示 一个 字符 **************/
void LCD12864_char (unsigned char row,unsigned char line,unsigned char a)
{
LCD12864_address(row,line);
LCD12864_data(a);
}
/*******************************************************************/
// 在指定位置显示字符串
/*******************************************************************/
void LCD12864_string(unsigned char row,unsigned char line,unsigned char *s)
{
unsigned char LCD12864_temp;
LCD12864_address(row,line);
LCD12864_temp=*s;
while(LCD12864_temp != 0x00)
{
LCD12864_data(LCD12864_temp);
LCD12864_temp=*(++s);
}
}
/****************************
0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 上半屏行坐标,表示的是多少列
0x88 0x89 0x8a 0x8b 0x8c 0x8d 0x8e 0x8f 下半屏行坐标,每组8列,每列16位,共128位,
0x80
0x81
0x82
0x83
........
0x9f //列坐标,共32个,表示的是行数 ,分两个半屏,每个32行,共64行
//Y坐标 只是用来确定具体坐标,在哪一行
功能:图形模式下,显示(X,Y)点
输入:X(0~127) Y(0~63) 相对屏幕坐标
输出:无
点亮某一点的操作步骤: 1.求出水平坐标X对应的地址和是哪一位 0x80-----0x8f (范围0-15) X/16求地址 X%16求该地址哪一位
2.求垂直坐标Y对应的地址和上下半屏 0x80------0x9f(范围0-63) Y本身就是8位地址,Y=63-Y ,Y--(0-31)
3.写入行列地址(Y是行X是列),0x80+Y ,0X80+X/16
4.读要显示的数据 DAT
5.区分上下半屏(X%16<=7&&X%16>=0是上半屏)写入数据每一位 DAT|0x80 ;DAT<<1
注意:这个函数显示某一点时,可能会把上次显示的处于同一地址的其他位的点擦掉,所以先保存所有数据,最后显示,就连贯起来了
*******************************/
/*******************************************************************/
/**************************************************************/
//------------------清整个GDRAM空间----------------------------
/**************************************************************/
void clrgdram()
{
unsigned char x,y ;
for(y=0;y<64;y++)
for(x=0;x<16;x++)
{
LCD12864_command(0x34);
LCD12864_command(y+0x80);
LCD12864_command(x+0x80);
LCD12864_command(0x30);
LCD12864_data(0x00);
LCD12864_data(0x00);
}
}
/******************************************/
/*******8==========================================================================
功能:图形模式下,显示(X,Y)点
输入:X(0~127) Y(0~63)
输出:无
0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 上半屏行坐标,表示的是多少列,X地址
0x88 0x89 0x8a 0x8b 0x8c 0x8d 0x8e 0x8f 下半屏行坐标,X地址 (水平地址 )
0x80 (垂直地址)
0x81
0x82
0x83
........
0x9f //列坐标,共32个,表示的是行数 ,分两个半屏,每个32行,共64行
====================================================================**********/
void LCD12864_Drawpoint(uchar X,uchar Y)
{
uchar i= 0, j = 0,ok=0;
uchar temp1 = 0x00,temp2 = 0x00;
LCD12864_command(0x34); //8位,扩充指令,绘图关
LCD12864_command(0x36); //8位,扩充指令,绘图开
i = X/16; //计算出X字节地址(0X80-0X8F)
j = X%16; //计算出该字节的具体位(0-15)
//Y = 63 - Y;
if(Y>=0 && Y<=31)//判断上下半屏
{
ok=1;
}
else if(Y>=32 && Y<=63)//下半屏
{
Y = Y - 32;//Y只有0-31共32个 地址
i = i + 8;//X地址进入下半屏 (0X88-0X8F)
ok=1;
}
if(ok)
{
//读数据操作
LCD12864_command(0x80+Y); //第一步:设置Y坐标,读数据先写地址,写GDRAM时先写垂直地址(0X80-0X9F)
LCD12864_command(0x80+i); //第二步:设置X坐标
LCD12864_ReadData(); //第三步:空读取一次
temp1 =LCD12864_ReadData(); //第四步:读取高字节,先读高字节
temp2 =LCD12864_ReadData(); //第五步:读取低字节
//图形模式下的写数据操作
LCD12864_command(0x80+Y); //第一步:设置Y坐标
LCD12864_command(0x80+i); //第二步:设置X坐标
if(j>=0 && j<=7) //判断是高字节
{
LCD12864_data(temp1|(0x80>>j)); //第三步:写高字节数据
LCD12864_data(temp2); //第四步:写低字节数据
}
else if(j>7 && j<=15) //判断是低字节
{
j = j - 8;
LCD12864_data(temp1);
LCD12864_data(temp2|(0x80>>j)); //改变字节里的位
}
}
}
/******************************************/
//画线
/********************************************/
//画水平线
void LCD12864_LineX(unsigned char X0, unsigned char X1, unsigned char Y)
{
unsigned char Temp ;
if( X0 > X1 )
{
Temp = X1 ; //交换X0 X1值
X1 = X0 ; //大数存入X1
X0 = Temp; //小数存入X0
}
for( ; X0 <= X1 ; X0++ )
LCD12864_Drawpoint(X0,Y);
}
//画垂直线
void LCD12864_LineY( unsigned char X, unsigned char Y0, unsigned char Y1)
{
unsigned char Temp ;
if( Y0 > Y1 )//交换大小值
{
Temp = Y1 ;
Y1 = Y0 ;
Y0 = Temp ;
}
for(; Y0 <= Y1 ; Y0++)
LCD12864_Drawpoint( X, Y0) ;
}
/******************************************/
/**************画图************************/
void LCD12864_DrawPicture( unsigned char code *pic)
{
unsigned char i, j, k ;
LCD12864_command(0x34);//开扩充指令
LCD12864_command(0x36);//开绘图功能
for( i = 0 ; i < 2 ; i++ )//分上下两屏写
{
for( j = 0 ; j < 32 ; j++)//垂直地址递加 ,行扫方式
{
LCD12864_command( 0x80 + j ) ;//写Y坐标(Y的范围: 0X80-0X9F )
if( i == 0 ) //写X坐标
{
LCD12864_command(0x80);//上半屏
}
else
{
LCD12864_command(0x88);//下半屏开始地址
}
for( k = 0 ; k < 16 ; k++ ) //写一整行数据
{
LCD12864_data( *pic++ );//前面只写入首地址,后面依次写入数据,地址会自动递增
}
}
}
LCD12864_command( 0x30);//恢复到一般模式
}
// 初始化设置
/*******************************************************************/
void LCD12864_init(void)
{
CLERADISPLAY // clear DDRAM
LCD12864_command(0x30); // 8 bits unsigned interface,basic instrument
LCD12864_command(0x02); // cursor return
LCD12864_command(0x0c); // display,cursor on
LCD12864_command(0x03);
LCD12864_command(0x06);
CLERADISPLAY // clear DDRAM
}
//
//显示函数
void display(unsigned long int sx,uchar j)
{
a1=sx/100000;
a2=sx%100000/10000;
a3=sx%10000/1000;//千位
a4=sx%1000/100;//百位
a5=sx%100/10;//十位
a6=sx%10;//个位
switch(j)
{
case 0x00: LCD12864_string(2,5," Ua ");break;
case 0x01: LCD12864_string(2,5," Ub ");break;
case 0x02: LCD12864_string(2,5," Uc ");break;
case 0x03: LCD12864_string(2,5," E ");break;
case 0x04: LCD12864_string(2,5," 转速 ");break;
case 0x05: LCD12864_string(2,5," 频率 ");break;
case 0x06: LCD12864_string(2,5,"脉冲计数");break;
case 0x07: LCD12864_string(2,5," ");break;
default :break;
}
LCD12864_command(0x90); //指定显示位置
LCD12864_data(num[a1]); //从最高位开始显示
LCD12864_data(num[a2]);
LCD12864_data(num[a3]);
LCD12864_data(num[a4]);
LCD12864_data(num[a5]);
LCD12864_data(num[10]);//小数点,前面测量计算时扩大了10倍,这里缩小回来
LCD12864_data(num[a6]);
}
/*********************************
主函数入口
/********************************************/
//主函数入口
//
main()
{
uchar ii=0;
CONTRL=0;
FLAG=0;
P0=0x00;
LED1=0;
LED1=1;
P0=0x00;
LED2=0;
LED2=1;
P0=0x00;
SHUCHU=0;//打开闸门
SHUCHU=1;
baohu();//判断采样数据保护
Mcu_init();
CLERADISPLAY
delays(1);
display(100000,7);
LCD12864_char(1,2,'A');
LCD12864_string(1,2,"shaozhanyu");
delays(2);
clrgdram();
CLERADISPLAY
delays(1);
clrgdram();
delays(1);
LCD12864_LineX(8,113,25);
clrgdram();
CLERADISPLAY
delays(2);
clrgdram();
LCD12864_LineY(55,29,57);
delays(2);
clrgdram();
delays(1);
LCD12864_DrawPicture(Bmp019);
delays(3);
Mcu_init();
CLERADISPLAY
LCD12864_string(3,1,"U V W E SP F CT");
LCD12864_char(2,1,'D');
LCD12864_string(4,1,"计数");
LCD12864_string(1,2,"少占鱼做");
delays(1);
/***************8888
P0=0x10;//怠速,准备打开K5继电器,关闭其他输出继电器
SHUCHU=0;//打开输出闸门
SHUCHU=1;//关闭闸门
outflag=0;//输出标志位
******************/
AD=0.0;
LCD12864_string(1,2,"灯光测试");
P0=0x41;
LED1=0;
LED1=1;
delayms(1000);
P0=0x42;
LED1=0;
LED1=1;
delayms(1000);
P0=0x44;
LED1=0;
LED1=1;
delayms(1000);
P0=0x48;
LED1=0;
LED1=1;
delayms(1000);
P0=0x50;
LED1=0;
LED1=1;
delayms(1000);
P0=0x60;
LED1=0;
LED1=1;
delayms(1000);
P0=0x41;
LED2=0;
LED2=1;
delayms(1000);
P0=0x42;
LED2=0;
LED2=1;
delayms(1000);
P0=0x44;
LED2=0;
LED2=1;
delayms(1000);
P0=0x48;
LED2=0;
LED2=1;
delayms(1000);
P0=0x50;
LED2=0;
LED2=1;
delayms(1000);
P0=0x60;
LED2=0;
LED2=1;
delayms(1000);
P0=0x00;
LED1=0;
LED1=1;
P0=0x00;
LED2=0;
LED2=1;
delayms(500);
LCD12864_string(1,2,"测继电器");
P0=0x04;//启动
SHUCHU=0;//打开闸门
delays(3);
SHUCHU=1;
P0=0x18;//停机
SHUCHU=0;//打开闸门
delays(3);
SHUCHU=1;
P0=0x40;//怠速,准备打开K5继电器,关闭其他输出继电器
SHUCHU=0;//打开输出闸门
delays(3);
SHUCHU=1;//关闭闸门
P0=0xa0;//准备合闸(交流,直流 内控制 )
SHUCHU=0;
delays(3);
SHUCHU=1;
P0=0x00;
SHUCHU=0;//打开闸门
SHUCHU=1;
keychuli(); //扫描并处理按键
delayms(600);
voltage();
LCD12864_string(3,1,"U V W E SP F ");
LCD12864_char(2,1,'D');
LCD12864_string(1,2,"少氏出品");
delays(11);
///初始化
LCD12864_string(4,1,"直流正常");
init();
while(1)
{
while(!FLAG); //等待频率测出
keychuli(); //扫描并处理按键
LCD12864_string(1,2,"测量电压");
delayms(500);
voltage(); //采样电压
LCD12864_string(1,2,"转换完成");
delayms(600);
baohu();//判断采样数据保护
for(;ii<6;)
{
if(xunhuanflag==0) //定点
{display(DAT[ii],ii);
LCD12864_string(1,2,"定点显示");
break;
}
display(DAT[ii],ii);
LCD12864_string(1,2,"循环显示");
delayms(2200);
keychuli();
ii++;
}//循环 显示结束
if(ii==6)
ii=0;
LCD12864_string(1,2,"下轮复位");
delayms(700);
init();
}
}
/*************************************/
//初始化函数
void init()
{
/******T1定时器模式,外部INT1控制开启,T0计数器不允许中断,外部控制
INTO开启,外部中断0允许(EX0=1),
定时器T2中断允许 (ET2=1) ************/
CONTRL=0;
FLAG=0;
EX0=0;
ET2=0;
//三个定时器方式设置
TMOD=0x9d; //T0T1方式控制
T2MOD=0x00;
T2CON=0x00;//定时器2,16位定时方式,自动重装。
TH0= 0x00; // T0高8位
TL0= 0x00; // T0低8位
TH1= 0x00; // T1高8位
TL1= 0x00; // T1低8位
EXEN2=0;
TH2=256/256;
TL2=256%256;
RCAP2H=256/256;
RCAP2L=256%256;
//中断设置 5
EX0=1;//允许外部0输入中断(INT0引脚)
ET2=1; //开定时中断2
IT0=1; //外部中断0边沿触发,下降沿到来触发
//优先级设置
PX0=1;
//预置T0,T1
TR1=1;//先允许T1定时,因T1的GATE=1,还要等外部INT1高电平才计数
TR0=1;//先允许T0计数 ,同T1一样,等待INTO高电平
TR2=1;//启动T2定时,不用外部控制,直接启动
EA=1; //开全局中断
CONTRL=1;
//初始化完成......
}
/**********************************
void reset()
{
CONTRL=0;
FLAG=0;
TL0=0x00;
TH0=0x00;
TL1=0x00;
TH1=0x00;
TF2=0;
TH2=256/256;
TL2=256%256;
TR1=1;//先允许T1定时,因T1的GATE=1,还要等外部INT1高电平才计数
TR0=1;//先允许T0计数 ,同T1一样,等待INTO高电平
TR2=1;//启动T2定时,不用外部控制,直接启动
EA=1; //开全局中断
CONTRL=1;
}
*******************************/
//键盘扫描
uchar scanf()
{
uchar value;
P0=0xff;
delayms(1);
SCANF=0;//打开键扫闸门
value=P0;
delayms(2);
value=P0;
SCANF=1;
return value;
}
/********************************/
//键处理
void keychuli()
{
uchar k;
//关于指示灯,交流是一组,直流是一组,其他状态用液晶显示
/***************************************/
/******************/
key=scanf();
/******************/
//启动键判断
if(key1==0&&key7==0&&DAT[4]==0)//启动位 ,油压和转速为0
{
for(k=0;k<3;k++)//三次启动循环
{
P0=0x04;//准备 输出K6继电器
SHUCHU=0;//打开闸门
delays(3);//隔三秒响应一次停机键
//响应停机键
key=scanf();
if(key0==0&&key7==1&&DAT[4]>500)//停机开关状态,油压高,转速达到500,其他继电器都停止工作 ,所以 ,P0=0x08
{
P0=0x18;//准备输出K0,K9继电器
SHUCHU=0;//打开输出闸门
SHUCHU=1;//关闭闸门
outflag=0;//输出标志位
}
if(key1==0&&key7==1&&DAT[4]>430) //每启动一次都判断是否成功,成功直接跳出
break ; //判断启动成功,立即跳出启动for 循环
delays(3);//没有启动成功,继续启动3秒
key=scanf();
if(key1==0&&key0==0&&key7==1&&DAT[4]>500)//停机,油压高,转速达到500,其他继电器都停止工作 ,所以 ,P0=0x08
{
P0=0x18;//准备输出K0,K9继电器
SHUCHU=0;//打开输出闸门
SHUCHU=1;//关闭闸门
outflag=0;//输出标志位
}
if(key1==0&&key7==1&&DAT[4]>430) //每启动一次都判断是否成功,成功直接跳出
break ;
delays(3);
key=scanf();
if(key0==0&&key7==1&&DAT[4]>500)//停机,油压高,转速达到500,其他继电器都停止工作 ,所以 ,P0=0x08
{
P0=0x18;//准备输出K0,K9继电器
SHUCHU=0;//打开输出闸门
SHUCHU=1;//关闭闸门
outflag=0;//输出标志位
}
if(key1==0&&key7==1&&DAT[4]>430) //每启动一次都判断是否成功,成功直接跳出
break ;
P0=0x18;//停止
SHUCHU=0;
SHUCHU=1;
delays(9);
}//for启动循环结束
SHUCHU=1;//关闭闸门
/**********************/
//启动失败判断
if(key7==0) //油压低
if(DAT[4]<440)
{
P0=0x01;//点亮启动失败灯
LED1=0;//开启573输入
LED1=1;//关闭使能,74HC573锁定状态
outflag=0;//输出标志位清0,表示输出未允许
}
}
//停机键判断
/********************/
if(key0==0&&key7==1&&DAT[4]>500)//停机,油压高,转速达到500,其他继电器都停止工作 ,所以 ,P0=0x08
{
P0=0x00;//准备交直流断闸(交流,直流 内控制 )
SHUCHU=0;
SHUCHU=1;
delayms(3);
P0=0x40;//怠速,准备打开K5继电器,关闭其他输出继电器
SHUCHU=0;//打开输出闸门
SHUCHU=1;//关闭闸门
outflag=0;
delays(29);
P0=0x18;//准备 输出K0和K9停油继电器
SHUCHU=0;//打开输出闸门
SHUCHU=1;//关闭闸门
outflag=0;//输出标志位
}
/*****************/
//应急键判断
if(key6==1)//应急/正常,高电位应急
{
eding=1;//应急标志
}
else if(key6==0) //进入怠速
{
eding=0;//怠速标志
}
if(eding==0)//对怠速的处理
{
P0=0x40;//怠速,准备打开K5继电器,关闭其他输出继电器
SHUCHU=0;//
SHUCHU=1;//关闭闸门
outflag=0;
}
if(eding==1&&outflag==0)//对额定的处理
{
P0=0x00;//额定,准备关闭K5继电器,进入额定,其他继电器都停止工作 ,所以 ,P0=0x00
SHUCHU=0;//打开输出闸门
SHUCHU=1;//关闭闸门
delayms(2);
if(DAT[0]>110&&DAT[1]>110&&DAT[2]>110&&DAT[5]>390)//三相交流大于110 ,频率大于390
{
P0=0xa0;//准备合闸(交流,直流 内控制 )
SHUCHU=0;
SHUCHU=1;
outflag=1;//合闸后,输出标志位置1
}
}
/******************************/
//循环键
if(key2==1) //处理循环定点显示标志位
xunhuanflag=1;
else if(key2==0)
xunhuanflag=0;
/*********************/
//灯光检查键
if(key4==0)//灯光检查
{
LED1=1;
LED2=1;
P0=0x7f;
LED1=0;
delayus(10);
LED1=1;
delayms(1000);
P0=0x7f;
LED2=0;
delayus(10);
LED2=1;
}
/************************/
//复位键
if(key5==0)//复位
{
P0=0x00;
LED1=0;
delayus(10);
LED1=1;
P0=0x00;
LED2=0;
delayus(10);
LED2=1;
}
/****************/
//自检键
if(key3==0) //自检
{ }
}
/**********保护函数*****************/
void baohu()
{
if(outflag==1)//前提是已经输出
{
//立即保护值
if((DAT[0]<800||DAT[1]<800||DAT[2]<800) || (DAT[0]>1800||DAT[1]>1800||DAT[2]>1800) || DAT[5]>4450||DAT[5]<3200)//立即断闸保护
{
P0=0x00;//准备断闸(交流,直流 内控制 )
SHUCHU=0;
SHUCHU=1;
outflag=0;//断闸后,输出标志位清0
if(DAT[0]>1800||DAT[1]>1800||DAT[2]>1800)
{
P0=0x80;//过压
LED1=0;
LED1=1;
}
if(DAT[5]>4450)
{
P0=0x80;//过频灯
LED2=0;
LED2=1;
}
if(DAT[0]<800||DAT[1]<800||DAT[2]<800)
{
P0=0x40;//欠压
LED1=0;
LED1=1;
}
if(DAT[5]<3200)
{
P0=0x40;//欠频灯
LED2=0;
LED2=1;
}
}//立即保护结束
// 延时保护值
if(DAT[0]<1000||DAT[1]<1000||DAT[2]<1000|| DAT[0]>1270||DAT[1]>1270||DAT[2]>1270|| DAT[5]>4300||DAT[5]<3700)
{
if(DAT[0]>1270||DAT[1]>1270||DAT[2]>1270)
{
P0=0x80;//过压
LED1=0;
LED1=1;
}
if(DAT[5]>4300)
{
P0=0x80;//过频
LED2=0;
LED2=1;
}
if(DAT[0]<1000||DAT[1]<1000||DAT[2]<1000)
{
P0=0x40;//欠压
LED1=0;
LED1=1;
}
if(DAT[5]<3700)
{
P0=0x40;//欠频
LED2=0;
LED2=1;
}
delays(4);//等待交流恢复
voltage();
if(DAT[0]>1100&&DAT[1]>1100&&DAT[2]>1100&&DAT[5]>3900)//三相交流大于110 ,频率大于390
{
P0=0x00;
LED1=0;
LED1=1;
P0=0x00;
LED2=0;
LED2=1;
P0=0xa0;//准备合闸(交流直流内控制 )
SHUCHU=0;
SHUCHU=1;
outflag=1;//合闸后,输出标志位置1
}
else
{
P0=0x00;//准备断闸(交流,直流 内控制 )
SHUCHU=0;
SHUCHU=1;
outflag=0;
}
}//交流和频率保护结束
//直流电压延时保护
if(DAT[3]>320||DAT[3]<170)
{if(DAT[3]>320)
{
LCD12864_string(4,1,"直流过压");
}
delays(4);//等待直流过压恢复
voltage();
if(DAT[3]>170&&DAT[3]<320)
{
LCD12864_string(4,1,"直流正常");
}
else
{P0=0x80;//关闭直流只开交流,因为前面已经检测过交流了,这里就不管了,当他正常
SHUCHU=0;
SHUCHU=1;
outflag=1;
LCD12864_string(4,1,"直流故障");
}
if(DAT[3]<170)
{
LCD12864_string(4,1,"直流欠压");
}
delays(2);//等待直流 欠压恢复
voltage();
if(DAT[3]>170&&DAT[3]<320)
{
LCD12864_string(4,1,"直流正常");
}
else
{P0=0x80;//关闭直流只开交流,因为前面已经检测过交流了,这里就不管了,当他正常
SHUCHU=0;
SHUCHU=1;
outflag=1;
LCD12864_string(4,1,"直流故障");
}
}//直流延时保护结束
}//总 保护结束
}//总函数结束
/*******************************/
//转速计算 ,频率计算
void zhuansu()
{
t1h=TH0;
t1l=TL0;
t2h=TH1;
t2l=TL1;
cnt1=t1l+(t1h<<8);
cnt2=t2l+(t2h<<8);
DAT[6]=cnt1/cnt2*1000000.20*10.00;//计数值
DAT[4]=cnt1/cnt2*1000000.200/124.00*600.00*10.0; //计算转速,信号频率就是单片机计数频率的整数倍 ,这里这样写是怕cnt1 cnt2 超出范围
//注意这里: cnt1 cnt2 的类型不能是 uint 否则第一步计算除法会得0 , 如果你要先乘1000000.0,也不行。因为超出了uint 范围
DAT[5]=DAT[4]*16.00/60.000*10.0;//电压频率计算
}
/******************************/
//外部中断0,调用转速计算
void interint0() interrupt 0 //using **
//外部中断0处理
{
EA=0;
zhuansu();//调用转速函数
FLAG=1;
/***注意:因为TO T1是外部引脚控制的,所以,这时外部低电平,自动停止。不用软件停止**/
}
void intertimer2() interrupt 5 //using **
//T2定时中断处理
{
TR2=0;
CONTRL=0;//关闭闸门信号
}
/*******************************/
//AD转换程序
/************************************************/
//常测数据函数
void voltage() //电压测量
{
uchar i;
AD=0.00;
X=0;
for(i=0;i<10;i++)
{
AD+=rd1543(0x08); //读取AD值
}
//
AD=AD/10.0;
X=AD*46.0001*50.00/1023.00;//转换成电压值 ,分辨率是10位
DAT[0]=X;
AD=0.00;
//
for(i=0;i<10;i++)
{
AD+=rd1543(0x08); //读取AD值
}
//
AD=AD/10.0;
X=AD*46.0001*50.00/1023.00;//转换成电压值 ,分辨率是10位
DAT[1]=X;
//
AD=0.00;
//
for(i=0;i<10;i++)
{
AD+=rd1543(0x08); //读取AD值
}
//
AD=AD/10.0;
X=AD*46.0001*50.00/1023.00;//转换成电压值 ,分辨率是10位
DAT[2]=X;
//
/*********
for(i=0;i<20;i++)
{
AD+=rd1543(0x07); //读取AD值
}
//
AD=AD/20;
X=AD*50.000/1023.000*28.500/4.000;
DAT[3]=X;
//
**********/
}
/***********************************************/
//TLC1543输入模拟电压范围: 0-4.9152 V
//TLC1543AD 10个时钟方式 方式1 。 LC1543 有四位精度 。 输入 0.0024v 时,AD值为0000000001
//0.0048时,还为1。 0.0072为 2 也就是0.0048 为一个 宽度 0.0048*AD 就是电压值 .
uint rd1543(uchar addr)
{
uint date_out=0;
uchar k;
// uchar j;
CLK=0;
CS=0;
ADDRESS=(bit)(addr&0x08); //用这种愚蠢的方法比用FOR循环快的多 。
CLK=1;
CLK=0;
addr=addr*2; //用乘法比用左移快
ADDRESS=(bit)(addr&0x08);
CLK=1;
CLK=0;
addr=addr*2; //用乘法比用左移快
ADDRESS=(bit)(addr&0x08);
CLK=1;
CLK=0;
addr=addr*2; //用乘法比用左移快
ADDRESS=(bit)(addr&0x08);
CLK=1;
CLK=0;
addr=addr*2; //用乘法比用左移快
// for (j=0;j<6;j++) //填充6 个CLOCK
// {
CLK=1;CLK=0; //这里不用循环,省时间
CLK=1;CLK=0;
CLK=1;CLK=0;
CLK=1;CLK=0;
CLK=1;CLK=0;
CLK=1;CLK=0;
CLK=0;
// }
CS=1;
delayus(8); //等待AD 转换
CS=0;
for(k=0;k<10;k++)
{
SDATA=1; //非P0口作为数据总线使用时,读入数据前要赋值1,特别
CLK = 1; //是既用于写有用于读的情况下.
date_out<<=1;
if(SDATA) date_out += 1; //这样写法比下面的方法速度快(5us)
// date_out=date_out|SDATA;//用时6US
CLK = 0;
}
return(date_out);
}
这篇关于TLC1543交流电压测试(单片机)教训版(千万注意电压型电路供流能力问题,注意器件属于电压输入型还是电流输入型)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!