0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

DWIN触摸屏的驱动设计与实现

CHANBAEK 来源:木南创智 作者:尹家军 2022-12-08 11:19 次阅读

有些时候嵌入式系统也需要显示更为复杂的图形,需要更丰富的数据展示。为此,我们需要更大,色彩更丰富,带触屏的显示屏,当然性价比更高就最好了。在我们的项目中遇到此类需求,我们有时会选择DWIN触摸屏。在本篇中,我们就来设计并实现DWIN触摸屏的驱动。

1、功能概述

  我们这里所说的是迪文的串口屏,该屏有多种接口类型,有使用RS485接口的屏,也有可通过跳线实现TTL接口或RS232接口的屏。但不论什么接口均采用相同的通讯协议。迪文串口屏采用的通讯协议的完整指令结构如下图所示:

Dingtalk_20221206154648.jpg

  其中,CRC校验不包括帧头和数据长度,仅针对指令和数据进行校验。CRC 校验采用 ANSI CRC-16 (X16+X15+X2+1)格式。当启用 CRC 帧校验并开启自动应答功能后(R2.4=1,RC.3=1),DGUS 屏会在 CRC 校验完成后自动应答校验情况,返回指令结构如下:

帧头 +02+(DGUS 屏接收的)指令 +数据(0xFF 表示CRC校验正确,0x00 **表示**CRC 校验错误) +CRC。

Dingtalk_20221206154648.jpg

  迪文的DGUS 把用户图形界面的每一个页面分解成多个控件变量,即 DGUS 屏采用变量驱动模式工作,屏的工作模式和GUI的状态完全由数据变量来控制。因此,串口指令也只需要对变量进行读、写即可,指令集非常简单,一共只有5条指令。读写指令集如下图所示:

Dingtalk_20221206154648.jpg

  配置寄存器空间是用于存放指令状态的,比如RTC(实时时间)、背光亮度等实时的状态。了解寄存器的地址以及各寄存器的功能,就可以通过串口指令来实现上位机与DGUS屏信息传输及控制。寄存器地址0x00~0xFF,具体功能查看迪文寄存器功能说明。

2、驱动设计与实现

  已经了解了迪文屏的通讯协议,我们就可以据此编写迪文屏的驱动程序。我们知道迪文屏的通讯协议有5个指令,我们的驱动就是通过这5个指令操作迪文屏。

2.1、对象定义

  我们们依然采用基于对象的操作方式来实现,所以首先我们依然是定义迪文屏的对象类型。具体定义如下:

/* 定义迪文串口屏对象类型 */
typedef struct DwinObject {

    DwinCheckCodeType checkMode;       //校验方式
    void (*SendData)(uint8_t *txData,uint16_t length);   //发送数据
    void (*GetRegister)(struct DwinObject *dwin,uint8_t regAddress,uint8_t readByteLength);
    void (*SetRegister)(struct DwinObject *dwin,uint8_t regAddress,uint8_t *txData,uint16_t length);
}DwinObjectType;

  迪文屏对象类型我们并没有抽象出太多属性,因为屏作为从设备并没有返回太多信息,也没有什么选择特性。考虑到通讯信息的校验可以选择是否启用,所以我们将其抽象为属性以区别于不同的情况。

  在对象使用之前同样需要对其初始化,所以我们需要对象初始化函数。初始化函数如下:

/* 初始化迪文串口屏对象 */
void DwinInitialization(DwinObjectType *dwin,DwinCheckCodeType checkMode,SendDataForDwinType SendData)
{
    if((dwin==NULL)||(SendData==NULL))
    {
       return;
    }
   
    dwin->checkMode=checkMode;
    dwin->SendData=SendData;
   
    dwin->GetRegister=GetRegisterDataFromDwinLCD;
    dwin->SetRegister=SetRegisterDataToDwinLCD;
}

2.2、对象操作

  定义并初始化过的对象就可以对其进行操作。我们已经说过,迪文屏通讯协议有5个操作码。分别是:0x80、写寄存器;0x81,读寄存器;0x82,写数据存储器;0x83,读数据存储器;0x84,写曲线缓冲区。我们对屏的操作就是实现对这5个操作码的使用。

2.2.1、写寄存器

  向指定的寄存器地址写入数据,指令码为0x80。该命令支持多个寄存器的连续写操作,但最多只能写入16个字节的数据。我们按照前面说的消息帧的格式编写操作函数如下:

/*写寄存器数据,一次最多允许写16个字节,即length<=16*/
static void SetRegisterDataToDwinLCD(DwinObjectType *dwin,uint8_t regAddress,uint8_t *txData,uint16_t length)
{
/*命令的长度由帧头(2个字节)+数据长度(1个字节)+指令(1个字节)+寄存器地址(1个字节)+写的数据(最多16字节)+CRC校验(2个字节)*/
uint16_t cmd_Length=length+5;
uint8_t cmd_Reg_Write[23];
cmd_Reg_Write[0]=0x5A;
cmd_Reg_Write[1]=0xA5;
cmd_Reg_Write[2]=(uint8_t)(length+2);
cmd_Reg_Write[3]= FC_REG_Write;
cmd_Reg_Write[4]=regAddress;
for(int dataIndex=0;dataIndex5]=txData[dataIndex];
}
   
    if(dwin->checkMode>DwinNone)
    {
       uint16_t checkCode=CalcDwinCRC16(&cmd_Reg_Write[3],length+2);
       cmd_Reg_Write[length+5]=(uint8_t)checkCode;
       cmd_Reg_Write[length+6]=(uint8_t)(checkCode>>8);
       cmd_Length=cmd_Length+2;
    }
   
dwin->SendData(cmd_Reg_Write,cmd_Length);
}

2.2.2、读寄存器

  从指定的寄存器地址开始读取指定字节长度的数据,指令码为0x81。一次读取一到多个寄存器。由于寄存器地址是0x00到0xFF,所以理论上可以一次读取全部寄存器。我们可以根据消息格式编写操作函数如下:

/*读寄存器数据*/
static void GetRegisterDataFromDwinLCD(DwinObjectType *dwin,uint8_t regAddress,uint8_t readByteLength)
{
/*命令的长度由帧头(2个字节)+数据长度(1个字节)+指令(1个字节)+寄存器地址(1个字节)+读取寄存器的字节长度(1个字节)+CRC校验(2个字节)*/
uint16_t cmd_Length=6;
uint8_t cmd_Reg_Read[]={0x5A0xA50x03,FC_REG_Read,0x000x000x000x00};//读数据命令
cmd_Reg_Read[4]=regAddress;
cmd_Reg_Read[5]=readByteLength;
   
    if(dwin->checkMode>DwinNone)
    {
       uint16_t checkCode=CalcDwinCRC16(&cmd_Reg_Read[3],3);
       cmd_Reg_Read[6]=(uint8_t)checkCode;
       cmd_Reg_Read[7]=(uint8_t)(checkCode>>8);
       cmd_Length=cmd_Length+2;
    }
   
dwin->SendData(cmd_Reg_Read,cmd_Length);
}

2.2.3、写存储器

  从指定的变量存储器地址开始写入数据串(字数据)到变量存储区,指令码为0x82。存储区与寄存器不一样,地址和数据都是16位的。理论上说一次可写差不多100个字的数据,事实上通常不建议这种极限方式。所以我们将长度限制在100个字节以内。我们可以根据消息格式编写操作函数如下:

/*写数据变量存储器,一次最多允许写47个字,即length<=94*/
void WriteFlashDataToDwinLCD(DwinObjectType *dwin,uint16_t startAddress,uint8_t *txData,uint16_t length)
{
/*命令的长度由帧头(2个字节)+数据长度(1个字节)+指令(1个字节)+起始地址(2个字节)+数据(长度为length)+CRC校验(2个字节)*/
uint16_t cmd_Length=length+6;
uint8_t cmd_VAR_Write[102];
cmd_VAR_Write[0]=0x5A;
cmd_VAR_Write[1]=0xA5;
cmd_VAR_Write[2]=(uint8_t)(length+3);
cmd_VAR_Write[3]= FC_VAR_Write;
cmd_VAR_Write[4]=(uint8_t)(startAddress>>8);//起始地址
cmd_VAR_Write[5]=(uint8_t)startAddress;//起始地址
for(int dataIndex=0;dataIndex6]=txData[dataIndex];
}

if(dwin->checkMode>DwinNone)
{
   uint16_t checkCode=CalcDwinCRC16(&cmd_VAR_Write[3],length+2);
   cmd_VAR_Write[length+6]=(uint8_t)checkCode;
   cmd_VAR_Write[length+7]=(uint8_t)(checkCode>>8);
   cmd_Length=cmd_Length+2;
}
   
dwin->SendData(cmd_VAR_Write,cmd_Length);
}

2.2.4、读存储器

  从变量存储区指定地址开始读取指定字长度的字数据,指令码为0x83。读取操作理论也可以读取256个字节,其实显示屏主要用于数据展示,主要是接收主机发来的数据。需要发送给主站的数据很有限。我们可以根据消息格式编写操作函数如下:

/*读变量存储器数据*/
void ReadFlashDataFromDwinLCD(DwinObjectType *dwin,uint16_t startAddress,uint8_t readWordLength)
{
/*命令的长度由帧头(2个字节)+数据长度(1个字节)+指令(1个字节)+起始地址(2个字节)+读取的字长度(1个字节)+CRC校验(2个字节)*/
uint16_t cmd_Length=7;
uint8_t cmd_VAR_Read[]={0x5A0xA50x04,FC_VAR_Read,0x000x000x000x000x00};//读数据命令
cmd_VAR_Read[4]=(uint8_t)(startAddress>>8);//起始地址
cmd_VAR_Read[5]=(uint8_t)startAddress;//起始地址
cmd_VAR_Read[6]=readWordLength;//读取长度
 
if(dwin->checkMode>DwinNone)
{
  uint16_t checkCode=CalcDwinCRC16(&cmd_VAR_Read[3],4);
  cmd_VAR_Read[7]=(uint8_t)checkCode;
  cmd_VAR_Read[8]=(uint8_t)(checkCode>>8);
  cmd_Length=cmd_Length+2;
}
   
dwin->SendData(cmd_VAR_Read,cmd_Length);
}

2.2.5、写曲线缓冲区

  DGUS屏有一个16KB、可存储8条曲线趋势图的曲线缓冲区,用于用户简单、快速显示曲线。曲线缓冲区的数据都是16位无符号数。写曲线缓冲区的指令码为0x84。我们可以根据消息格式编写操作函数如下:

/*写曲线缓冲区,一次最多允许写8个字,即length<=16*/
void WriteCurveToDwinLCD(DwinObjectType *dwin,uint8_t *txData,uint16_t length,uint8_t channelMode)
{
/*命令的长度由帧头(2个字节)+数据长度(1个字节)+指令(1个字节)+通道模式(1个字节)+数据(length,最多8个字)+CRC校验(2个字节)*/
uint16_t cmd_Length=length+5;
uint8_t cmd_Curve_Write[23];//写曲线缓冲区命令
cmd_Curve_Write[0]=0x5A;
cmd_Curve_Write[1]=0xA5;
cmd_Curve_Write[2]=(uint8_t)(length+2);
cmd_Curve_Write[3]= FC_Curve_Write;
cmd_Curve_Write[4]=channelMode;
for(int dataIndex=0;dataIndex5]=txData[dataIndex];
}

if(dwin->checkMode>DwinNone)
{
  uint16_t checkCode=CalcDwinCRC16(&cmd_Curve_Write[3],length+2);
  cmd_Curve_Write[length+5]=(uint8_t)checkCode;
  cmd_Curve_Write[length+6]=(uint8_t)(checkCode>>8);
  cmd_Length=cmd_Length+2;
}
   
dwin->SendData(cmd_Curve_Write,cmd_Length);
}

3、驱动的使用

  我们已经实现了迪文触摸屏的驱动,接下来我们就使用驱动开发应用。驱动的使用并不复杂,依然是定义对象,然后根据需要操作对象。

3.1、声明并初始化对象

  首先我们需要使用DwinObjectType类型声明一个迪文触摸屏的对象变量。这就是一个具体的屏对象,具体如下:

  DwinObjectType lcd;

  当然这个对象还不能使用,因为器并未赋值。所以我们还要使用DwinInitialization函数初始化这个对象。在初始化之前我们必须定义一个形如void (*SendDataForDwinType)(uint8_t *txData,uint16_t length)的函数,具体如下:

//数据发送
void SendData(uint8_t *txData,uint16_t length)
{
uint16_t i;
for(i=0;i//传送寄存器不为空,等待传送结束
 while(USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET)
{
}
 // 写一个字节到对应的串口传送数据寄存器
 USART_SendData(USART3, txData[i]);
}
}

  并将函数指针传递作为参数传递给初始化函数。除了屏对象和发送数据函数指针外,初始化函数还有一个参数是校验方式。这里我们选择无校验码,所以初始化函数调用如下:

  DwinInitialization(&lcd,DwinNone,SendData);

  到这里对象的定义及初始化就完成了。

3.2、调用函数操作对象

  初始化之后的对象就可对其进行操作了。我们在前面已经针对5个操作码实现了对对象的驱动。那么我们要操作对象时,就是调用这5个函数来实现的。

  向屏的数据存储区写数据时,需要调用WriteFlashDataToDwinLCD函数,如我们要向0x0000地址开始写入8个字节的数据则:

  WriteFlashDataToDwinLCD(&lcd,0x0000,txData,8);

  从屏的数据存储区读取数据时,需要调用ReadFlashDataFromDwinLCD函数,如我们从0x000A地址开始读取4个字长度的数据则:

  ReadFlashDataFromDwinLCD(&lcd,0x000A,4);

  向曲线缓冲区写数据,总共有8个通道,一次最多允许写8个字。通道模式用于选择向哪些通道写数据,每一位代表一个通道。所以我们在使用WriteCurveToDwinLCD函数写曲线缓冲区时需要配置通道。比如我们要向8个通道写8个字的数据则:

  WriteCurveToDwinLCD(&lcd,txData,16,0xFF);

  对于寄存器的读写操作,我们封装了一些常用的,如读取LCD系统时间、校准LCD系统时间等。

  读取LCD系统时间:GetDateTimeFromDwinLCD(&lcd);

  校准LCD系统时间:CalibrationDateTimeForDwinLCD(&lcd,dateTime);

  音乐播放控制:HandleDwinLCDToPlayMusic(&l'c'd,playStart,playNum,volume);当playNum为0时表示停止播放。

  设置屏显示画面:SetDwinLCDDisplay(&lcd,picID);

  对于没有封装的寄存器操作,可以直接在对象中调用寄存器读写函数实现。如:

  lcd.GetRegister(&lcd, regAddress,readByteLength);

  lcd.SetRegister(&lcd,regAddress,txData,length);

4、应用总结

  我们通过实测,驱动迪文触摸屏的操作结果与预期一致。我们让MCU给显示屏发送一些数据,并在屏上显示出来:

Dingtalk_20221206154648.jpg

  再来看看对传感器做一下扰动时(用配气仪和小型气泵向传感器管道送不同的气)数据的变化,传感器检测对象变化是屏幕显示也变化。

Dingtalk_20221206154648.jpg

  再来改变一下气体成分和气泵的转速看看数据的变化:

Dingtalk_20221206154648.jpg

  经过以上实验,迪文串口屏驱动已经达到预期。至于一些更复杂的操作方式也都可以以此为基础实现之。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 触摸屏
    +关注

    关注

    42

    文章

    2131

    浏览量

    113654
  • 驱动设计
    +关注

    关注

    1

    文章

    108

    浏览量

    15187
  • DWIN
    +关注

    关注

    0

    文章

    1

    浏览量

    1734
收藏 人收藏

    评论

    相关推荐

    101. 触摸屏按键常常点不到,客户说触摸屏反应迟钝,难道是坏了

    触摸屏
    电子学习
    发布于 :2022年12月24日 18:58:58

    小编科普怎样去使用DWIN

    DWIN使用方法总结(上)DWIN使用方法总结(上)DWIN介绍开发工具ICL生成CFG修
    发表于 01-26 06:32

    什么是DWIN?怎样使用DWIN

    DWIN使用方法总结(下)DWIN使用方法总结(下)数据帧常用的系统指令常用控件基础触控按键返回数据变量录入图标变量数据变量显示总结DWIN
    发表于 02-23 07:07

    电阻式触摸屏的基本结构和驱动原理

    电阻式触摸屏的基本结构和驱动原理:四线电阻式触摸屏的结构如上图,在玻璃或丙烯酸基板上覆盖有两层透平,均匀导电的ITO层,分别做为X电极和Y电极,它们之间由均匀排列的
    发表于 04-10 23:14 105次下载
    电阻式<b class='flag-5'>触摸屏</b>的基本结构和<b class='flag-5'>驱动</b>原理

    触摸屏实现原理及在android上的实现

    触摸屏实现原理及在android上的实现 是啊触摸屏的扩展应用
    发表于 05-23 18:21 3次下载

    LM3S8962驱动触摸屏

    LM3S8962驱动触摸屏
    发表于 11-18 09:41 17次下载

    手机触摸屏驱动的研究与设计张欣

    手机触摸屏驱动的研究与设计_张欣
    发表于 03-14 08:00 6次下载

    组态王和触摸屏哪个好_组态王和触摸屏区别

    现在组态软件和触摸屏都是市场上边较成熟的产品,组态软件的出现并没有取代触摸屏触摸屏触摸屏的优势,组态软件有组态软件的特点。组态软件和触摸屏
    发表于 11-29 17:11 3.4w次阅读

    四线电阻触摸屏校准算法的实现

    本文介绍了四线电阻触摸屏技术参数和四线电阻式触摸屏的三大特点,其次介绍了四线电阻式触摸屏的工作原理,最后介绍了四线电阻触摸屏校准算法的实现
    发表于 01-21 10:19 1.8w次阅读

    电阻式触摸屏的结构和实现原理介绍

    很多LCD模块都采用了电阻式触摸屏,这些触摸屏等效于将物理位置转换为代表X、Y坐标的电压值的传感器。通常有4线、5线、7线和8线触摸屏实现,本文详细介绍了SAR结构、四种
    的头像 发表于 12-11 09:35 2.1w次阅读
    电阻式<b class='flag-5'>触摸屏</b>的结构和<b class='flag-5'>实现</b>原理介绍

    Linux下的触摸屏驱动

    对于触摸屏驱动,我们主要需要掌握触摸屏驱动代码和应用层测试代码。下面讲的是基于Mini2440的触摸屏
    发表于 04-26 14:45 2240次阅读

    Android4.2触摸屏驱动与4.0有哪些不同

    本文档的主要内容详细介绍的是Android4.2触摸屏驱动与Android4.0触摸屏驱动的差别。
    发表于 07-29 17:36 1次下载
    Android4.2<b class='flag-5'>触摸屏</b><b class='flag-5'>驱动</b>与4.0有哪些不同

    STM32F427V系列的触摸屏驱动

    STM32F427V系列的触摸屏驱动提示:本程序主控为STM32F427VGT6,LCD驱动为ILI9341触摸驱动为2046文章目录STM
    发表于 12-27 19:13 11次下载
    STM32F427V系列的<b class='flag-5'>触摸屏</b><b class='flag-5'>驱动</b>

    STM32F1开发指南笔记36----触摸屏

    本章,介绍如何使用STM32F1来驱动触摸屏,战舰STM32F103本身并没有触摸屏控制器,但是它支持触摸屏,可以通过外接带触摸屏的LCD模
    发表于 12-31 19:36 30次下载
    STM32F1开发指南笔记36----<b class='flag-5'>触摸屏</b>