创建基于DLL的Proteus VSM仿真模型
2013-03-05
silingsong
标签: Proteus

6.打开VC,新建工程,选择Win32 Dynamic-Link Library,给工程命名,建立空的DLL工程。从Proteus安装目录的INCLUDE文件夹中将VSM.HPP复制到当前工程目录,新建文件 LCD19264A.H和LCD19264A.CPP,编写如下代码。

CODE:

/*****************************************************************

* 文件:LCD19264A.H

* 说明:不支持以下特性

* (1) 不支持显示开关控制

* (2) 不支持设置显示起始行

*****************************************************************/

#include "vsm.hpp"

//LCD常量

#define LCD_BLK_NUM3//lcd block number

#define LCD_BLK_LEN64//lcd block length

#define LCD_LINE_NUM 8//lcd line number

#define LCD_LENGTH(LCD_BLK_LEN*LCD_BLK_NUM)//lcd length

#define LCD_WIDTH64//lcd width

#define BLANK_WIDTH50//the width of blank

#define SYM_LINEWIDTH 28//the width of symbol line

//LCD命令掩码

#define CMD_MASK0xc0

//LCD命令

#define DISP_ONOFF0x00 //开关背光

#define SET_STARTLINE 0xc0 //设置起始行

#define SET_XADDRESS 0x80 //设置X地址

#define SET_YADDRESS 0x40 //设置Y地址

//延时常量

#define DELAY_1s1000000000000

#define DELAY_1ms 1000000000

#define DELAY_1us 1000000

#define DELAY_1ns 1000

#define DELAY_1ps 1

/*

LCD元件既有数字电气特性,也有绘图特性,所以要继承IACTIVEMODEL和IDSIMMODEL

*/

class LCD19264A : public IACTIVEMODEL,public IDSIMMODEL

{

public:

/* 电气模型成员函数 */

//数字电路总是返回TRUE

INT isdigital (CHAR *pinname);

//当创建模型实例时被调用,做初始化工作

VOID setup (IINSTANCE *inst, IDSIMCKT *dsim);

//仿真运行模式控制,交互仿真中每帧开始时被调用

VOID runctrl (RUNMODES mode);

//交互仿真时用户改变按键等的状态时被调用

VOID actuate (REALTIME time, ACTIVESTATE newstate);

//交互仿真时每帧结束时被调用,通过传递ACTIVEDATA数据与绘图模型通信,从而调用animate()进行绘图

BOOL indicate (REALTIME time, ACTIVEDATA *data);

//当引脚状态变化时被调用,主要用来处理数据输入和输出

VOID simulate (ABSTIME time, DSIMMODES mode);

//可通过setcallback()设置在给定时间调用的回调函数

VOID callback (ABSTIME time, EVENTID eventid);

/* 绘图模型成员函数 */

//当创建模型实例时被调用,做初始化工作

VOID initialize (ICOMPONENT *cpt);

//被PROSPICE调用,返回模拟电气模型

ISPICEMODEL *getspicemodel (CHAR *device);

//被PROSPICE调用,返回数字电气模型

IDSIMMODEL *getdsimmodel (CHAR *device);

//当原理图需要重绘时被调用

VOID plot (ACTIVESTATE state);

//当相应的电气模型产生活动事件时被调用,常用来更新图形

VOID animate (INT element, ACTIVEDATA *newstate);

//用来处理键盘和鼠标事件

BOOL actuate (WORD key, INT x, INT y, DWORD flags);

private:

IINSTANCE *instance; //PROSPICE仿真原始模型

IDSIMCKT *ckt;//DSIM的数字元件

ICOMPONENT *component; //ISIS内部一个活动组件对象

//引脚定义

IDSIMPIN *di; //D/I

IDSIMPIN *rw; //R/W

IDSIMPIN *en; //E

IDSIMPIN *cs1; //CS1

IDSIMPIN *cs2; //CS2

IDSIMPIN *cs3; //CS3

IDSIMPIN *d[8]; //D0~D7

IBUSPIN *databus; //D[0..7]

//LCD参数

BYTE x_addr; //X地址(见手册)

BYTE y_addr; //Y地址(见手册)

BYTE status; //状态(见手册)

BYTE cur_blk; //当前块号(总共分3块,见手册)

BYTE DDRAM[LCD_BLK_NUM][LCD_BLK_LEN*LCD_WIDTH/8]; //LCD显示RAM

BOOL new_flag; //新数据到达标志

//显示参数

BOX lcdarea; //LCD显示区域

float pix_width, pix_height; //每象素对应矩形的宽和高

};

CODE:

/*****************************************************************

* 文件:LCD19264A.CPP

* 说明:不支持以下特性

* (1) 不支持显示开关控制

* (2) 不支持设置显示起始行

*****************************************************************/

#include

#include "LCD19264A.h"

//----------------------------------------------------------------------------

//电气模型的实现

//构造数字电气模型实例

extern "C" IDSIMMODEL __declspec(dllexport) * createdsimmodel (CHAR *device, ILICENCESERVER *ils)

{

//授权认证

ils->authorize(0x88888888, 0x69); //版本为6.9

return new LCD19264A; //创建模型实例

}

//析构数字电气模型实例

extern "C" VOID __declspec(dllexport) deletedsimmodel (IDSIMMODEL *model)

{

delete (LCD19264A *)model; //删除模型实例

}

//数字电路总是返回TRUE

INT LCD19264A::isdigital (CHAR *pinname)

{

return 1;

}

//当创建模型实例时被调用,做初始化工作

VOID LCD19264A::setup (IINSTANCE *inst, IDSIMCKT *dsim)

{

instance = inst; //PROSPICE仿真原始模型

ckt = dsim;//DSIM的数字元件

//获取引脚

di = instance->getdsimpin("D/I,d/i", true);

di->setstate(FLT); //FLOAT

rw = instance->getdsimpin("R/W,r/w", true);

rw->setstate(FLT);

en = instance->getdsimpin("E,e", true);

en->setstate(FLT);

cs1 = instance->getdsimpin("CS1,cs1", true);

cs1->setstate(FLT);

cs2 = instance->getdsimpin("CS2,cs2", true);

cs2->setstate(FLT);

cs3 = instance->getdsimpin("CS3,cs3", true);

cs3->setstate(FLT);

d[0] = instance->getdsimpin("D0,d0", true);

d[0]->setstate(FLT);

d[1] = instance->getdsimpin("D1,d1", true);

d[1]->setstate(FLT);

d[2] = instance->getdsimpin("D2,d2", true);

d[2]->setstate(FLT);

d[3] = instance->getdsimpin("D3,d3", true);

d[3]->setstate(FLT);

d[4] = instance->getdsimpin("D4,d4", true);

d[4]->setstate(FLT);

d[5] = instance->getdsimpin("D5,d5", true);

d[5]->setstate(FLT);

d[6] = instance->getdsimpin("D6,d6", true);

d[6]->setstate(FLT);

d[7] = instance->getdsimpin("D7,d7", true);

d[7]->setstate(FLT);

//为方便操作,将D0~D7映射为8位总线

databus = instance->getbuspin("LCD_DBUS", d, 8);

databus->settiming(100,100,100); //设置时间延迟

databus->setstates(SHI,SLO,FLT); //设置总线逻辑为[1,0,三态]时的驱动状态

//lcd model

x_addr = 0; //X地址(见手册)

y_addr = 0; //Y地址(见手册)

status = 0; //状态(见手册)

new_flag = TRUE; //新数据到达标志

}

//仿真运行模式控制,交互仿真中每帧开始时被调用

VOID LCD19264A::runctrl (RUNMODES mode)

{

}

//交互仿真时用户改变按键等的状态时被调用

VOID LCD19264A::actuate (REALTIME time, ACTIVESTATE newstate)

{

}

//交互仿真时每帧结束时被调用,通过传递ACTIVEDATA数据与绘图模型通信,从而调用animate()进行绘图

BOOL LCD19264A::indicate (REALTIME time, ACTIVEDATA *data)

{

if(new_flag){ //有新数据到达

data->type = ADT_REAL; //call back animate() to refresh lcd

data->realval = (float)time*DSIMTICK;

}

return TRUE;

}

//当引脚状态变化时被调用,主要用来处理数据输入和输出

VOID LCD19264A::simulate (ABSTIME time, DSIMMODES mode)

{

BYTE data;

if(en->isnegedge()){//E的下降沿到达

if((rw->istate()==SLO)||(rw->istate()==WLO)){ //R/W为低表示写

//读块选择

if((cs1->istate()==SLO)||(cs1->istate()==WLO))

cur_blk = 0;

else if((cs2->istate()==SLO)||(cs2->istate()==WLO))

cur_blk = 1;

else if((cs3->istate()==SLO)||(cs3->istate()==WLO))

cur_blk = 2;

else

return; //not select block

data = (BYTE)databus->getbusvalue(); //读数据

if((di->istate()==SHI)||(di->istate()==WHI)){ //D/I为高表示数据

DDRAM[cur_blk][x_addr*LCD_BLK_LEN+y_addr] = data; //写入数据

new_flag = TRUE; //新数据到达标志

y_addr = ((y_addr+1)%LCD_BLK_LEN);//y地址自动加1

if(y_addr==0)

x_addr = ((x_addr+1)%LCD_LINE_NUM); //自动换行

}else{//D/I为低表示命令

switch(data&CMD_MASK)

{

case DISP_ONOFF: //开关背光

break;

case SET_STARTLINE: //设置起始行

break;

case SET_XADDRESS: //设置X地址

x_addr = (data&0x07); //bit2~bit0

break;

case SET_YADDRESS: //设置Y地址

y_addr = (data&0x3f); //bit5~bit0

break;

default:

break;

}

}

}else{//E的下降沿到达,R/W为高表示读结束

databus->drivetristate(time); //驱动总线为三态

}

}else if(en->isposedge()//E的上升沿到达

&& ((rw->istate()==SHI)||(rw->istate()==WHI))){ //R/W为高表示读

if((di->istate()==SHI)||(di->istate()==WHI)){ //D/I为高表示数据

//读块选择

if((cs1->istate()==SLO)||(cs1->istate()==WLO))

cur_blk = 0;

else if((cs2->istate()==SLO)||(cs2->istate()==WLO))

cur_blk = 1;

else if((cs3->istate()==SLO)||(cs3->istate()==WLO))

cur_blk = 2;

else

return; //not select block

data = DDRAM[cur_blk][x_addr*LCD_BLK_LEN+y_addr];

databus->drivebusvalue(time, data);//输出数据

y_addr = ((y_addr+1)%LCD_BLK_LEN);//y地址自动加1

if(y_addr==0)

x_addr = ((x_addr+1)%LCD_LINE_NUM); //自动换行

}else{//D/I为低表示命令

databus->drivebusvalue(time, status); //输出状态

}

}

}

//可通过setcallback()设置在给定时间调用的回调函数

VOID LCD19264A::callback (ABSTIME time, EVENTID eventid)

{

}

//----------------------------------------------------------------------------

//绘图模型的实现

// Exported constructor for active component models.

extern "C" IACTIVEMODEL __declspec(dllexport) * createactivemodel (CHAR *device, ILICENCESERVER *ils)

{

ils->authorize (0x88888888,0x69); //6.9

return new LCD19264A;

}

// Exported destructor for active component models.

extern "C" VOID__declspec(dllexport) deleteactivemodel (IACTIVEMODEL *model)

{

delete (LCD19264A *)model;

}

//当创建模型实例时被调用,做初始化工作

VOID LCD19264A::initialize (ICOMPONENT *cpt)

{

//获取ICOMPONENT接口和初始化

component = cpt;

component->setpenwidth(0);

component->setpencolour(BLACK);

component->setbrushcolour(BLACK);

//获取显示区域

component->getsymbolarea(0,&lcdarea);

//计算每象素对应矩形的宽和高

pix_width = (float)(lcdarea.x2-lcdarea.x1-BLANK_WIDTH*2-SYM_LINEWIDTH*2)/LCD_LENGTH;

pix_height = (float)(lcdarea.y2-lcdarea.y1-BLANK_WIDTH*2-SYM_LINEWIDTH*2)/LCD_WIDTH;

}

//被PROSPICE调用,返回模拟电气模型

ISPICEMODEL *LCD19264A::getspicemodel (CHAR *)

{

return NULL;

}

//被PROSPICE调用,返回数字电气模型

IDSIMMODEL*LCD19264A::getdsimmodel (CHAR *)

{

return this;

}

//当原理图需要重绘时被调用

VOID LCD19264A::plot (ACTIVESTATE state)

{

//绘制LCD19264A_C元件基本图形

component->drawsymbol(-1);

//刷新LCD数据显示

new_flag = TRUE;

animate (0, NULL);

}

//当相应的电气模型产生活动事件时被调用,常用来更新图形

VOID LCD19264A::animate (INT element, ACTIVEDATA *data)

{

BOX pix;

BYTE dat,block,line,byte_off,bit_off;

if(new_flag){ //当有新数据到达

new_flag = FALSE;

component->begincache (lcdarea); //打开缓冲

component->drawsymbol(1);//显示LCD19264_1符号

//显示各点数据

for(block=0; block

for(line=0; line

for(byte_off=0; byte_off

dat = DDRAM[block][line*LCD_BLK_LEN+byte_off]; //get byte data

for(bit_off=0; bit_off<8; bit_off++){

if(dat&(1<

pix.x1 = (int)(BLANK_WIDTH+(block*LCD_BLK_LEN+byte_off)*pix_width+0.5);

pix.y1 = -(int)(BLANK_WIDTH+(line*8+bit_off)*pix_height+0.5);

pix.x2 = pix.x1 + (int)(pix_width+0.5);

pix.y2 = pix.y1 - (int)(pix_height+0.5);

component->drawbox(pix); //绘制1个象素点

}

}

}

}

}

component->endcache(); //结束缓冲,显示数据

}

}

//用来处理键盘和鼠标事件

BOOL LCD19264A::actuate (WORD key, INT x, INT y, DWORD flags)

{

return FALSE;

}

7.搭建电路如下电路,新建Keil C工程,编写代码测试元件。如下图:

LCD19264A仿真模型和源码下载

共 2 页   上一页12
可能会用到的工具/仪表
本站简介 | 意见建议 | 免责声明 | 版权声明 | 联系我们
CopyRight@2024-2039 嵌入式资源网
蜀ICP备2021025729号