EDN首页   博客首页

最新日志

发表于:2008-10-28 10:22:15
标签:ST7920  汉字点阵  LCD  直接方式  

5

ST7920汉字点阵LCD的接口程序(直接接方式)

//总线扩展方式连接12832点阵汉字液晶
//A0--D/I
//A1--R/W
//E连接地址分配的0xD000

#include <absacc.h>
#include <REG52.H>

#define CW_Addr XBYTE[0xD000]
#define CR_Addr XBYTE[0xD002]
#define DW_Addr XBYTE[0xD001]
#define DR_Addr XBYTE[0xD003]

unsigned char DisBuf1[17];
unsigned char DisBuf2[17];

void InitLCD()
{
    //wait for 40mS
    while(CR_Addr & 0x80);    //等待BF忙标志
    CW_Addr = 0x30;    //Function Set: 8bit MPU interface,基本指令集
    //wait for 100uS
    while(CR_Addr & 0x80);    //等待BF忙标志
    CW_Addr = 0x30;    //Function Set: 8bit MPU interface,基本指令集
    //wait for 37uS
    while(CR_Addr & 0x80);    //等待BF忙标志
    CW_Addr = 0x0C;    //显示状态:整体显示ON,光标OFF,光标反白OFF
    //wait for 100us
    while(CR_Addr & 0x80);    //等待BF忙标志
    CW_Addr = 0x01;    //清屏
    //wait for 10mS
    while(CR_Addr & 0x80);    //等待BF忙标志
    CW_Addr = 0x06;    //进入点设定:光标右移,AC+1
}

void ReInitLCD()
{
    //wait for 40mS
    while(CR_Addr & 0x80);    //等待BF忙标志
    CW_Addr = 0x30;    //Function Set: 8bit MPU interface,基本指令集
    //wait for 100uS
    while(CR_Addr & 0x80);    //等待BF忙标志
    CW_Addr = 0x30;    //Function Set: 8bit MPU interface,基本指令集
    //wait for 37uS
    while(CR_Addr & 0x80);    //等待BF忙标志
    CW_Addr = 0x0F;    //显示状态:整体显示ON,光标ON,光标反白ON
    //wait for 100us
    while(CR_Addr & 0x80);    //等待BF忙标志
    CW_Addr = 0x06;    //进入点设定:光标右移,AC+1
}


void DisplayBuff0()
{
    unsigned char i;
    while(CR_Addr & 0x80);    //等待BF忙标志
    CW_Addr = 0x80;
    for(i=0;i<16;i++)
    {
        while(CR_Addr & 0x80);    //等待BF忙标志
        DW_Addr = DisBuf1[i];
    }
}

void DisplayBuff1()
{
    unsigned char i;
    while(CR_Addr & 0x80);    //等待BF忙标志
    CW_Addr = 0x90;
    for(i=0;i<16;i++)
    {
        while(CR_Addr & 0x80);    //等待BF忙标志
        DW_Addr = DisBuf2[i];
    }
}

主程序调用示例
    sprintf(DisBuf1,"一二三四技术公司");
    sprintf(DisBuf2,"系统自检中      ");
    DisplayBuff0();
    DisplayBuff1();

    sprintf(DisBuf1,"体积总量:     m3");
    sprintf(DisBuf2," %12.3f   ",massflow);        //体积总量
    DisplayBuff0();
    DisplayBuff1();

系统分类: 单片机   |    用户分类:    |    来源: 原创

评论(0) | 阅读(323)
发表于:2008-10-28 10:11:20
标签:ST7920  汉字点阵  LCD  间接方式  

4

ST7920汉字点阵LCD的接口程序(间接方式)

/**********************************************************
*            ST7920控制器间接方式驱动程序                   *
*            12832点阵  使用P0和                           *
*               RS,RW,E                                  *
*               2006.1                                    *
**********************************************************/
/******************/
/**/
#include <reg52.h>
#include <intrins.h>


sbit RS   = P2^4;
sbit RW   = P2^5;
sbit E   = P3^5;

unsigned char DisBuf1[17];   //第一行的显示缓冲
unsigned char DisBuf2[17];   //第二行的显示缓冲

unsigned char ReadInst()    //读BF标志及AC计数器
{
    unsigned char temp;
   
    EA = 0;
    RS = 0;        //0:指令,1:数据
    RW = 1;        //0:写,1:读
    E = 1;
    temp = P0;
    E = 0;
    EA = 1;
    return(temp);   
}

unsigned char ReadData()
{
    unsigned char temp;
    EA = 0;
    RS = 1;        //0:指令,1:数据
    RW = 1;        //0:写,1:读
    E = 1;
    temp = P0;
    E = 0;
    EA = 1;
    return(temp);   
}

void WriteInst(unsigned char Inst)
{
    EA = 0;
    RS = 0;        //0:指令,1:数据
    RW = 0;        //0:写,1:读
    P0 = Inst;
    E = 1;
    _nop_();
    E = 0;
  EA = 1;
}

void WriteData(unsigned char Inst)
{
  EA = 0;
    RS = 1;        //0:指令,1:数据
    RW = 0;        //0:写,1:读
    P0 = Inst;
    E = 1;
    _nop_();
    E = 0;
  EA = 1;
}



void InitLCD()
{
    //wait for 40mS
    while(ReadInst() & 0x80);    //等待BF忙标志
//    {
//        if(i--)break;
//    }
    WriteInst(0x30);    //Function Set: 8bit MPU interface,基本指令集
    //wait for 100uS
    while(ReadInst() & 0x80);    //等待BF忙标志
    WriteInst(0x30);    //Function Set: 8bit MPU interface,基本指令集
    //wait for 37uS
    while(ReadInst()& 0x80);    //等待BF忙标志
//    WriteInst(0x0F);    //显示状态:整体显示ON,光标ON,光标反白ON
    WriteInst(0x0C);    //显示状态:整体显示ON,光标OFF,光标反白OFF
    //wait for 100us
    while(ReadInst() & 0x80);    //等待BF忙标志
    WriteInst(0x01);    //清屏
    //wait for 10mS
    while(ReadInst()& 0x80);    //等待BF忙标志
    WriteInst(0x06);    //进入点设定:光标右移,AC+1
}

void DispStr(unsigned char StartAddr,unsigned char *star)
{
    unsigned char temp;
    while(ReadInst() & 0x80);    //等待BF忙标志
    WriteInst(StartAddr|0x80);
    while(*star!='\0')
    {
        while(ReadInst() & 0x80);    //等待BF忙标志
        temp = *star;
        WriteData(temp);
        star++;
    }
}

void DisplayBuff(unsigned char line)
{
    unsigned char i;
    while(ReadInst() & 0x80);    //等待BF忙标志
    WriteInst(0x80+0x10*line);
    for(i=0;i<16;i++)
    {
        while(ReadInst() & 0x80);    //等待BF忙标志
        WriteData(DisBuf[i+0x10*line]);
    }
}

void DisplayBuff0()     //显示第一行
{
    unsigned char i;
    while(ReadInst() & 0x80);    //等待BF忙标志
    WriteInst(0x80);
    for(i=0;i<16;i++)
    {
        while(ReadInst() & 0x80);    //等待BF忙标志
        WriteData(DisBuf1[i]);
    }
}

void DisplayBuff1()        //显示第二行
{
    unsigned char i;
    while(ReadInst() & 0x80);    //等待BF忙标志
    WriteInst(0x90);
    for(i=0;i<16;i++)
    {
        while(ReadInst() & 0x80);    //等待BF忙标志
        WriteData(DisBuf2[i]);
    }
}


主程序调用示例
    sprintf(DisBuf1,"一二三四技术公司");
    sprintf(DisBuf2,"系统自检中      ");
    DisplayBuff0();
    DisplayBuff1();

    sprintf(DisBuf1,"体积总量:     m3");
    sprintf(DisBuf2," %12.3f   ",massflow);        //体积总量
    DisplayBuff0();
    DisplayBuff1();

系统分类: 单片机   |    用户分类:    |    来源: 原创

评论(0) | 阅读(251)
发表于:2008-10-21 8:46:27
标签:键盘扫描  源程序  

2

一个经典的按键扫描程序

按键是比较复杂。可以用状态机表示。
每10mS执行一次键盘扫描任务
0、无键,若有键进入状态1
1、第一次检到有键。若有键进入状态2,同时将键值送缓冲区。 若无键进入状态0。
2、若有键则计时,按键超过300ms进入状态3,同时将键值送缓冲区。 若无键进入状态1。
  表示第一次按键后如果长按键则300ms后认为有一次按键。
3、若有键则计时,按键超过200ms则将键值送缓冲区。 若无键进入状态1。
  表示长按键则以后每200ms后认为有一次按键。

void KeyScan()    //每10mS执行一次键盘扫描任务
{
    switch(KeyState)
    {
        case 0:
            if(KeyIsKeyDown())  //有键
            {
                KeyState = 1;
            }
            break;
        case 1:
            if(KeyIsKeyDown())  //有键
            {
                KeyState = 2;
                KeyBufIn();   //将键值送缓冲区
                KeyStartRptCnt = 0;
            }
            else
            {
                KeyState = 0;
            }
            break;
        case 2:
            if(KeyIsKeyDown())  //有键
            {
                if(KeyStartRptCnt++ >= 30)
                {
                    KeyState = 3;
                    KeyRptCnt = 0;
                    KeyBufIn();
                }
            }
            else
            {
                KeyState = 1;
            }
            break;
        case 3:
            if(KeyIsKeyDown())  //有键
            {
                if(KeyRptCnt++ >= 20)
                {
                    KeyRptCnt = 0;
                    KeyBufIn();
                }
            }
            else
            {
                KeyState = 1;
            }
            break;
        default:
            break;
    }
}

系统分类: 单片机   |    用户分类:    |    来源: 原创

评论(1) | 阅读(474)
发表于:2008-10-11 16:09:02
标签:WTC  测井仪器  有线遥传  

2

生产测井仪器--有线遥传短接

   该仪器采用有线多路遥传技术实现单芯电缆传输。 可以配DDL-Ⅲ、DDL-Ⅴ及所有与DDL-Ⅲ相兼容的地面系统。

遥传短节(WTC)原理
遥传短节核心由两片单片机组成,主要向井下仪器各参数发送地址,并
接收各参数返回的数据,将其编成曼彻斯特码送至地面进行处理。

点击看大图

单片机 2每4ms 由发出一组地址信号,通过保护电路加载电路上载到TPS 总线,TPS 总线上所接的仪器根据TPS 总线上的地址发回相
应的数据,经整形缓冲后输入到单片机2,单片机2 将数据
传给单片机1,由单片机1编码成曼彻斯特编码输出,经叠加放大、电缆驱动
后上载到CBS 总线。

系统分类: 工业控制   |    用户分类:    |    来源: 原创

评论(0) | 阅读(296)
发表于:2008-9-17 16:30:01
标签:无标签

2

谈谈质量流量计

    质量流量计销售量每年增长超过30%,在高精度流量产品中更是占据了主要市场份额。预计在2010年全球高精度流量产品中质量流量计所占份额将为40%-50%,占有10-12亿美元的销售量。
    质量流量计是增长速度最快的一种流量仪表,也是现在测量精度最高的流量仪表之一.行业领先者高准公司(MicroMotion)的ELITE系列可以达到+/-0.05%的精度。
发展简史:
50年代提出原理
70年代美国人发明振动式科氏质量流量计
77年正式应用现场。
90年代初随成套设备进入中国后被用户所了解,开始大量应用。
由于其高准确度、高可靠性,非接触式等优点,被广泛用于石油、石化、化工、食品、制药等行业。
    质量流量计的测量部件主要是振动管。有弯管和直管之分。其基本原理是:采用自激振荡的办法是振动管振动。其振动管的振荡周期的平方和管内介质的密度成正比。在振动管的两侧放置速度式传感器,信号是两路正弦波。两路正弦波之间的时间差和质量流量成正比。
    生产厂家主要有:艾默生过程管理旗下的高准公司、E+H公司、Rheonik公司、ABB公司、科隆KROHNE、丹佛斯公司等。国内厂家有太原航空仪表有限公司流量仪表厂、上海一诺仪表有限公司、西安东风机电有限公司、北京首科实华自动化设备有限公司、北京科力博奥仪表技术有限公司、北京普瑞三元仪表有限公司、乐清市东仪成套有限公司、大连中隆等。
    质量流量计发展很快,其变送器经历了全模拟电路实现、大规模数字电路发展到DSP全数字结算。产品性能不断提高。产品稳定性也非常好。因为其无可动部件,寿命大大加长。是容积式仪表无法比拟的。与速度式仪表相比,它没有直管段要求。它受温度、压力、介质密度、粘度的影响非常小。
    质量流量计用于密闭管道的液体或气体测量,它不能测量气液两相的介质。液体含气对精度影响非常大。

系统分类: 工业控制   |    用户分类:    |    来源: 原创

评论(0) | 阅读(381)
发表于:2008-9-10 9:53:20
标签:无标签

2

好郁闷,居然被逻辑运算符难住了。

使用C#编程
UInt16 c,crc=0xffff,a=0x00ff;
c = crc & a;

c = crc & a;报错,搞得我晕头转向的。错误CS0266: 无法将类型“int”隐式转换为“ushort”。存在一个显式转换(是否缺少强制转换?)

我是同类型的呀,难道运算符重载后会把两个UInt16计算成Int32?
试了几个方法,问了几个人。

看样子必须使用显式转换了
c = Convert.ToUInt16(d & a);通过了
c#类型太严格了

系统分类: 工业控制   |    用户分类:    |    来源: 原创

评论(0) | 阅读(331)
发表于:2008-9-8 12:37:01
标签:初始化参数  

2

PC端程序初始化参数的处理。

PC端的许多初始化参数需要保存,我对PC机的编程是很怵的。
还是在编WM6.0下的通讯软件。使用VS2005下的C#开发。
初始化参数我见到的有这么几种。
1、使用ini文件:好像说是.net不推荐使用,就没有深入学习了。
2、使用注册表。这是MS推荐使用的,但俺怕麻烦。觉得还是绿色软件好一些。
3、使用XML。.net对XML文件的支持力度很强。俺决心就用它了。

我的XML文件是这样的。
<?xml version="1.0" encoding="utf-8"?>
<Modbus Version="1.00.00">
  <CommPort>COM1</CommPort>
  <MassUnit>T</MassUnit>
</Modbus>
编程思路是首先读取ModbusIni.xml,如果文件不存在则创建这个文件,如果文件存在则读取文件中的参数,最后在程序关闭时保存设置好的参数到ModbusIni.xml。
首先定义两个变量,mDocument代表XML文件,mCurrentNode表示选择好的节点。
        private XmlDocument mDocument;
        private XmlNode mCurrentNode;
        public Form1()
        {
            InitializeComponent();
            foreach (string s in SerialPort.GetPortNames())
            {
                comboBox1.Items.Add(s);   //通讯端口的选择
            }
     
            bool bSave = false;
            mDocument = new XmlDocument();
            try
            {
                mDocument.Load(@"ModbusIni.xml");//判断文件Load正确否
            }
            catch
            {
                // 走到这里就失败了,文件不存在或其它错误
                bSave = true;
                CreatXmlDocument();//创建文件
            }
            if (!bSave)
            {
                ReadXmlDocument();
            }
        }

        private void CreatXmlDocument()               //建立新的文件          
        {
            //定义XML文档头文件
            XmlDeclaration xmlDeclaration = mDocument.CreateXmlDeclaration("1.0", "utf-8", null);
            //增加XML文档头
            mDocument.AppendChild(xmlDeclaration);
            //定义XML的根
            XmlElement xmlRoot = mDocument.CreateElement("Modbus");
            //添加XML的根
            mDocument.AppendChild(xmlRoot);
            //添加根的属性
          xmlRoot.SetAttribute("Version", "1.00.00");
          XmlElement newCommPort = mDocument.CreateElement("CommPort");
          XmlElement newMassUnit = mDocument.CreateElement("MassUnit");
     
            XmlText CommPort = mDocument.CreateTextNode("COM1");
            XmlText MassUnit = mDocument.CreateTextNode("T");

            newCommPort.AppendChild(CommPort);
            newMassUnit.AppendChild(MassUnit);

            //添加XML根的节点
            xmlRoot.AppendChild(newCommPort);
            xmlRoot.AppendChild(newMassUnit);

            // Save the document to a file.
            mDocument.Save("ModbusIni.xml");
        }
        private void ReadXmlDocument()               //读取Xml文件
        {
            XmlElement xmlRoot = mDocument.DocumentElement;
          //使用SelectSingleNode查找到想要的参数
            mCurrentNode = xmlRoot.SelectSingleNode("CommPort");
            comboBox1.Text = mCurrentNode.InnerText;

        }
        private void SaveXmlDocument()               //保存Xml文件
        {
            XmlElement xmlRoot = mDocument.DocumentElement;
//使用SelectSingleNode查找到想要的参数,
            mCurrentNode = xmlRoot.SelectSingleNode("CommPort");
            mCurrentNode.InnerText = comboBox1.Text ;

            mDocument.Save("ModbusIni.xml");
        }

        //程序退出时保存XML文件
        private void Form1_Closed(object sender, EventArgs e)
        {
            SaveXmlDocument();
        }

以上程序在VS2005下编译成功,在多普达P660上运行成功。

系统分类: 工业控制   |    用户分类:    |    来源: 原创

评论(0) | 阅读(421)
发表于:2008-8-4 12:52:15
标签:IEEE754  浮点转字节  

2

串行通讯中浮点数和整型数的处理办法

串行通讯是以字节为单位进行传送的,对于浮点数和整型数都需要进行转换才能进行通讯。

MCU和PC的浮点数都是基于IEEE754格式的。有4字节(float)、8字节(double)、10字节(有一些不支持)。这里以4字节(float)浮点数为例。


转化常见的方法有:
一、强制指针类型转换。
 //   转换Int数据到字节数组   
unsigned int intVariable,i;
unsigned char charArray[2];
(unsigned char) * pdata = ((unsigned char)*)&intVariable;  //进行指针的强制转换 
for(i=0;i<2;i++)
{
    charArray[i] = *pdata++;    
}    
//   转换float数据到字节数组
unsigned int i;
float floatVariable;
unsigned char charArray[4];
(unsigned char) * pdata = ((unsigned char)*)&floatVariable;  //进行指针的强制转换
for(i=0;i<4;i++)
{
    charArray[i] = *pdata++;    
}
//   转换字节数组到int数据
unsigned int   intVariable="0";
unsigned char  i;
void   *pf;    
pf   =&intVariable;
(unsigned char) * px = charArray; 
for(i=0;i<2;i++)
{
 *(((unsigned char)*)pf+i)=*(px+i);    

//   转换字节数组到float数据
float   floatVariable="0";
unsigned char  i;
void   *pf;    
pf   =&floatVariable;
(unsigned char) * px = charArray; 
for(i=0;i<4;i++)
{
 *(((unsigned char)*)pf+i)=*(px+i);    
}  
二、使用结构和联合,这是我最喜欢的方法
定义结构和联合如下
typedef union {struct {unsigned char low_byte;
           unsigned char mlow_byte;
           unsigned char mhigh_byte;
           unsigned char high_byte;
          }float_byte;
       struct {unsigned int low_word;
          unsigned int high_word;
          }float_word;
       float  value;
      }FLOAT;

typedef union   {
        struct {
        unsigned char low_byte;
        unsigned char high_byte;
        } d1;
    unsigned int value;
    } INT;


使用方法:
对于浮点数:
FLOAT floatVariable;在程序中直接使用floatVariable.float_byte.high_byte,floatVariable.float_byte.mhigh_byte,
floatVariable.float_byte.mlow_byte,floatVariable.float_byte.low_byte这四个字节就可以方便的进行转换了。
对于整数:
INT intVariable;在程序中直接使用intVariable.value.high_byte,intVariable.value.low_byte就OK了。
三、对整型数可以用数学运算的方法进行转换
unsigned int intVariable;
unsigned char low_byte = intVariable%256;
unsigned char high_byte = intVariable/256;


系统分类: 单片机   |    用户分类:    |    来源: 原创

评论(0) | 阅读(389)
发表于:2008-7-31 9:38:55
标签:串口  通讯  

3

串口接收二进制数的显示问题。

串口通讯由于下位机一般都是MCU,不支持Unicode编码。我们采用二进制数据进行通讯。接收的数据为byte[]格式的字节串。而PC机的显示都是Unicode编码的string字符串。我们需要进行转化。
下面代码ToCharString()是byte[]格式的字节串转化成HEX十六进制数的显示方式。例如MCU发送“12345”,接收将显示“3132333435”。
 ToCharString()是 byte[]格式的字节串转化成Unicode编码的string字符串的显示方式 。例如MCU发送“12345”,接收将显示“12345”。


      static char[] hexDigits = {
        '0', '1', '2', '3', '4', '5', '6', '7',
        '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

        public static string ToHexString(byte[] bytes)
        {
            char[] chars = new char[bytes.Length * 2];
            for (int i = 0; i < bytes.Length; i++)
            {
                int b = bytes[i];
                chars[i * 2] = hexDigits[b >> 4];
                chars[i * 2 + 1] = hexDigits[b & 0xF];
            }
            return new string(chars);
        }
        public static string ToCharString(byte[] bytes)
        {
            char[] chars = new char[bytes.Length];
            for (int i = 0; i < bytes.Length; i++)
            {
                chars[i ] = (char)bytes[i];
               
            }
            return new string(chars);
        }

系统分类: 工业控制   |    用户分类:    |    来源: 原创

评论(0) | 阅读(675)
发表于:2008-7-30 20:10:09
标签:serialPort  通讯  Modbus  Windows  Mobile  

2

Windows Mobile 6下使用serialPort控件进行串口通讯。

在仪表的Modbus通讯中,上位机可以是PLC、PC、PDA或智能手机。本人使用Windows Mobile 6操作系统下的多普达P660进行了上位机的编程。现在将调试程序说一下。

使用VS2005进行开发。

控件有3个button,两个TextBox,两个Label和一个SerialPort等。button1打开串口,button2将txtSend的字符发出,接收是自动的。接收txtReceive显示的是字符ASCII码的十进制数字,例如发送“12345”,txtReceive显示为“4950515253”。

txtReceive显示使用了在线程上异步执行指定委托。使用BeginInvoke和delegate完成。

接收使用事件private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;

namespace modbuscomm
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private  String strReceive ;
        public delegate void InvokeDelegate();
        public void Display()
        {
            txtReceive.Text = strReceive;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //更改参数
            serialPort1.PortName = "COM6";
            serialPort1.BaudRate = 9600;
           // serialPort1.Parity = Parity.Odd; 默认是none
            serialPort1.StopBits = StopBits.One;

            //打开串口(打开串口后不能修改端口名,波特率等参数,修改参数要在串口关闭后修改)
            serialPort1.Open();

        }

        private void button2_Click(object sender, EventArgs e)
        {
            //发送数据
            //SendStringData(serialPort1);
            //serialPort1.Write(txtSend.Text);
            //也可用字节的形式发送数据
            SendBytesData(serialPort1); 
        }
 

  //发送字符串数据
                private   void   SendStringData(SerialPort   serialPort)
                {
                        serialPort.Write(txtSend.Text);
                }


                //发送二进制数据
                private   void   SendBytesData(SerialPort   serialPort)
                {
                        byte[]   bytesSend="System".Text.Encoding.Default.GetBytes(txtSend.Text   );
                        serialPort.Write(bytesSend,   0,   bytesSend.Length);
                }

        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {

                //   接收缓冲区中数据的字节数
                int int_Len = serialPort1.BytesToRead;

                //   接收数据
                byte[] bytes = new byte[int_Len];
                serialPort1.Read(bytes, 0, int_Len);


                //   将数据存入字符串缓冲区中
                for (int i = 0; i < bytes.Length; i++)
                {
                    strReceive += bytes[i];
                }
                strReceive += "";
           
            txtReceive.BeginInvoke(new InvokeDelegate(Display));
        }

       } 
}  

 

系统分类: 工业控制   |    用户分类:    |    来源: 原创

评论(0) | 阅读(549)
23下一页总共 , 当前 /