建设直播网站需要多少钱,科技软件公司,韩都衣舍网站建设的改进,河南夏邑网站建设有些时候嵌入式系统也需要显示更为复杂的图形#xff0c;需要更丰富的数据展示。为此#xff0c;我们需要更大#xff0c;色彩更丰富#xff0c;带触屏的显示屏#xff0c;当然性价比更高就最好了。在我们的项目中遇到此类需求#xff0c;我们有时会选择DWIN触摸屏。在本… 有些时候嵌入式系统也需要显示更为复杂的图形需要更丰富的数据展示。为此我们需要更大色彩更丰富带触屏的显示屏当然性价比更高就最好了。在我们的项目中遇到此类需求我们有时会选择DWIN触摸屏。在本篇中我们就来设计并实现DWIN触摸屏的驱动。
1、功能概述 我们这里所说的是迪文的串口屏该屏有多种接口类型有使用RS485接口的屏也有可通过跳线实现TTL接口或RS232接口的屏。但不论什么接口均采用相同的通讯协议。迪文串口屏采用的通讯协议的完整指令结构如下图所示 其中CRC校验不包括帧头和数据长度仅针对指令和数据进行校验。CRC 校验采用 ANSI CRC-16 X16X15X21格式。当启用 CRC 帧校验并开启自动应答功能后R2.41RC.31DGUS 屏会在 CRC 校验完成后自动应答校验情况返回指令结构如下
帧头**02****DGUS 屏接收的指令数据0xFF 表示 CRC **校验正确0x00 表示 CRC **校验错误CRC。** 迪文的DGUS 把用户图形界面的每一个页面分解成多个控件变量即 DGUS 屏采用变量驱动模式工作屏的工作模式和GUI的状态完全由数据变量来控制。因此串口指令也只需要对变量进行读、写即可指令集非常简单一共只有5条指令。读写指令集如下图所示 配置寄存器空间是用于存放指令状态的比如RTC实时时间、背光亮度等实时的状态。了解寄存器的地址以及各寄存器的功能就可以通过串口指令来实现上位机与DGUS屏信息传输及控制。寄存器地址0x00~0xFF具体功能查看迪文寄存器功能说明。
2、驱动设计与实现 已经了解了迪文屏的通讯协议我们就可以据此编写迪文屏的驱动程序。我们知道迪文屏的通讯协议有5个指令我们的驱动就是通过这5个指令操作迪文屏。
2.1、对象定义 我们们依然采用基于对象的操作方式来实现所以首先我们依然是定义迪文屏的对象类型。具体定义如下
/* 定义迪文串口屏对象类型 */
typedef struct DwinObject {DwinCheckCodeType checkMode; //校验方式void (*SendData)(uint8_t *txDatauint16_t length); //发送数据void (*GetRegister)(struct DwinObject *dwinuint8_t regAddressuint8_t readByteLength);void (*SetRegister)(struct DwinObject *dwinuint8_t regAddressuint8_t *txDatauint16_t length);
}DwinObjectType;迪文屏对象类型我们并没有抽象出太多属性因为屏作为从设备并没有返回太多信息也没有什么选择特性。考虑到通讯信息的校验可以选择是否启用所以我们将其抽象为属性以区别于不同的情况。 在对象使用之前同样需要对其初始化所以我们需要对象初始化函数。初始化函数如下
/* 初始化迪文串口屏对象 */
void DwinInitialization(DwinObjectType *dwinDwinCheckCodeType checkModeSendDataForDwinType SendData)
{if((dwinNULL)||(SendDataNULL)){return;}dwin-checkModecheckMode;dwin-SendDataSendData;dwin-GetRegisterGetRegisterDataFromDwinLCD;dwin-SetRegisterSetRegisterDataToDwinLCD;
}2.2、对象操作 定义并初始化过的对象就可以对其进行操作。我们已经说过迪文屏通讯协议有5个操作码。分别是0x80、写寄存器0x81读寄存器0x82写数据存储器0x83读数据存储器0x84写曲线缓冲区。我们对屏的操作就是实现对这5个操作码的使用。
2.2.1、写寄存器 向指定的寄存器地址写入数据指令码为0x80。该命令支持多个寄存器的连续写操作但最多只能写入16个字节的数据。我们按照前面说的消息帧的格式编写操作函数如下
/*写寄存器数据一次最多允许写16个字节即length16*/
static void SetRegisterDataToDwinLCD(DwinObjectType *dwinuint8_t regAddressuint8_t *txDatauint16_t length)
{/*命令的长度由帧头2个字节数据长度1个字节指令1个字节寄存器地址1个字节写的数据(最多16字节)CRC校验2个字节*/uint16_t cmd_Lengthlength5;uint8_t cmd_Reg_Write[23];cmd_Reg_Write[0]0x5A;cmd_Reg_Write[1]0xA5;cmd_Reg_Write[2](uint8_t)(length2);cmd_Reg_Write[3] FC_REG_Write;cmd_Reg_Write[4]regAddress;for(int dataIndex0;dataIndexlength;dataIndex){cmd_Reg_Write[dataIndex5]txData[dataIndex];}if(dwin-checkModeDwinNone){uint16_t checkCodeCalcDwinCRC16(cmd_Reg_Write[3]length2);cmd_Reg_Write[length5](uint8_t)checkCode;cmd_Reg_Write[length6](uint8_t)(checkCode8);cmd_Lengthcmd_Length2;}dwin-SendData(cmd_Reg_Writecmd_Length);
}2.2.2、读寄存器 从指定的寄存器地址开始读取指定字节长度的数据指令码为0x81。一次读取一到多个寄存器。由于寄存器地址是0x00到0xFF所以理论上可以一次读取全部寄存器。我们可以根据消息格式编写操作函数如下
/*读寄存器数据*/
static void GetRegisterDataFromDwinLCD(DwinObjectType *dwinuint8_t regAddressuint8_t readByteLength)
{/*命令的长度由帧头2个字节数据长度1个字节指令1个字节寄存器地址1个字节读取寄存器的字节长度1个字节CRC校验2个字节*/uint16_t cmd_Length6;uint8_t cmd_Reg_Read[]{0x5A0xA50x03FC_REG_Read0x000x000x000x00};//读数据命令cmd_Reg_Read[4]regAddress;cmd_Reg_Read[5]readByteLength;if(dwin-checkModeDwinNone){uint16_t checkCodeCalcDwinCRC16(cmd_Reg_Read[3]3);cmd_Reg_Read[6](uint8_t)checkCode;cmd_Reg_Read[7](uint8_t)(checkCode8);cmd_Lengthcmd_Length2;}dwin-SendData(cmd_Reg_Readcmd_Length);
}2.2.3、写存储器 从指定的变量存储器地址开始写入数据串字数据到变量存储区指令码为0x82。存储区与寄存器不一样地址和数据都是16位的。理论上说一次可写差不多100个字的数据事实上通常不建议这种极限方式。所以我们将长度限制在100个字节以内。我们可以根据消息格式编写操作函数如下
/*写数据变量存储器一次最多允许写47个字即length94*/
void WriteFlashDataToDwinLCD(DwinObjectType *dwinuint16_t startAddressuint8_t *txDatauint16_t length)
{/*命令的长度由帧头2个字节数据长度1个字节指令1个字节起始地址2个字节数据长度为lengthCRC校验2个字节*/uint16_t cmd_Lengthlength6;uint8_t cmd_VAR_Write[102];cmd_VAR_Write[0]0x5A;cmd_VAR_Write[1]0xA5;cmd_VAR_Write[2](uint8_t)(length3);cmd_VAR_Write[3] FC_VAR_Write;cmd_VAR_Write[4](uint8_t)(startAddress8);//起始地址cmd_VAR_Write[5](uint8_t)startAddress;//起始地址for(int dataIndex0;dataIndexlength;dataIndex){cmd_VAR_Write[dataIndex6]txData[dataIndex];}if(dwin-checkModeDwinNone){uint16_t checkCodeCalcDwinCRC16(cmd_VAR_Write[3]length2);cmd_VAR_Write[length6](uint8_t)checkCode;cmd_VAR_Write[length7](uint8_t)(checkCode8);cmd_Lengthcmd_Length2;}dwin-SendData(cmd_VAR_Writecmd_Length);
}2.2.4、读存储器 从变量存储区指定地址开始读取指定字长度的字数据指令码为0x83。读取操作理论也可以读取256个字节其实显示屏主要用于数据展示主要是接收主机发来的数据。需要发送给主站的数据很有限。我们可以根据消息格式编写操作函数如下
/*读变量存储器数据*/
void ReadFlashDataFromDwinLCD(DwinObjectType *dwinuint16_t startAddressuint8_t readWordLength)
{/*命令的长度由帧头2个字节数据长度1个字节指令1个字节起始地址2个字节读取的字长度1个字节CRC校验2个字节*/uint16_t cmd_Length7;uint8_t cmd_VAR_Read[]{0x5A0xA50x04FC_VAR_Read0x000x000x000x000x00};//读数据命令cmd_VAR_Read[4](uint8_t)(startAddress8);//起始地址cmd_VAR_Read[5](uint8_t)startAddress;//起始地址cmd_VAR_Read[6]readWordLength;//读取长度if(dwin-checkModeDwinNone){uint16_t checkCodeCalcDwinCRC16(cmd_VAR_Read[3]4);cmd_VAR_Read[7](uint8_t)checkCode;cmd_VAR_Read[8](uint8_t)(checkCode8);cmd_Lengthcmd_Length2;}dwin-SendData(cmd_VAR_Readcmd_Length);
}2.2.5、写曲线缓冲区 DGUS屏有一个16KB、可存储8条曲线趋势图的曲线缓冲区用于用户简单、快速显示曲线。曲线缓冲区的数据都是16位无符号数。写曲线缓冲区的指令码为0x84。我们可以根据消息格式编写操作函数如下
/*写曲线缓冲区一次最多允许写8个字即length16*/
void WriteCurveToDwinLCD(DwinObjectType *dwinuint8_t *txDatauint16_t lengthuint8_t channelMode)
{/*命令的长度由帧头2个字节数据长度1个字节指令1个字节通道模式1个字节数据length最多8个字CRC校验2个字节*/uint16_t cmd_Lengthlength5;uint8_t cmd_Curve_Write[23];//写曲线缓冲区命令cmd_Curve_Write[0]0x5A;cmd_Curve_Write[1]0xA5;cmd_Curve_Write[2](uint8_t)(length2);cmd_Curve_Write[3] FC_Curve_Write;cmd_Curve_Write[4]channelMode;for(int dataIndex0;dataIndexlength;dataIndex){cmd_Curve_Write[dataIndex5]txData[dataIndex];}if(dwin-checkModeDwinNone){uint16_t checkCodeCalcDwinCRC16(cmd_Curve_Write[3]length2);cmd_Curve_Write[length5](uint8_t)checkCode;cmd_Curve_Write[length6](uint8_t)(checkCode8);cmd_Lengthcmd_Length2;}dwin-SendData(cmd_Curve_Writecmd_Length);
}3、驱动的使用 我们已经实现了迪文触摸屏的驱动接下来我们就使用驱动开发应用。驱动的使用并不复杂依然是定义对象然后根据需要操作对象。
3.1、声明并初始化对象 首先我们需要使用DwinObjectType类型声明一个迪文触摸屏的对象变量。这就是一个具体的屏对象具体如下 DwinObjectType lcd; 当然这个对象还不能使用因为器并未赋值。所以我们还要使用DwinInitialization函数初始化这个对象。在初始化之前我们必须定义一个形如void (*SendDataForDwinType)(uint8_t *txDatauint16_t length)的函数具体如下
//数据发送
void SendData(uint8_t *txDatauint16_t length)
{uint16_t i;for(i0;ilength;i){//传送寄存器不为空等待传送结束while(USART_GetFlagStatus(USART3 USART_FLAG_TXE) RESET){}// 写一个字节到对应的串口传送数据寄存器USART_SendData(USART3 txData[i]);}
}并将函数指针传递作为参数传递给初始化函数。除了屏对象和发送数据函数指针外初始化函数还有一个参数是校验方式。这里我们选择无校验码所以初始化函数调用如下 DwinInitialization(lcdDwinNoneSendData); 到这里对象的定义及初始化就完成了。
3.2、调用函数操作对象 初始化之后的对象就可对其进行操作了。我们在前面已经针对5个操作码实现了对对象的驱动。那么我们要操作对象时就是调用这5个函数来实现的。 向屏的数据存储区写数据时需要调用WriteFlashDataToDwinLCD函数如我们要向0x0000地址开始写入8个字节的数据则 WriteFlashDataToDwinLCD(lcd0x0000txData8); 从屏的数据存储区读取数据时需要调用ReadFlashDataFromDwinLCD函数如我们从0x000A地址开始读取4个字长度的数据则 ReadFlashDataFromDwinLCD(lcd0x000A4); 向曲线缓冲区写数据总共有8个通道一次最多允许写8个字。通道模式用于选择向哪些通道写数据每一位代表一个通道。所以我们在使用WriteCurveToDwinLCD函数写曲线缓冲区时需要配置通道。比如我们要向8个通道写8个字的数据则 WriteCurveToDwinLCD(lcdtxData160xFF); 对于寄存器的读写操作我们封装了一些常用的如读取LCD系统时间、校准LCD系统时间等。 读取LCD系统时间GetDateTimeFromDwinLCD(lcd); 校准LCD系统时间CalibrationDateTimeForDwinLCD(lcddateTime); 音乐播放控制HandleDwinLCDToPlayMusic(l’c’dplayStartplayNumvolume);当playNum为0时表示停止播放。 设置屏显示画面SetDwinLCDDisplay(lcdpicID); 对于没有封装的寄存器操作可以直接在对象中调用寄存器读写函数实现。如 lcd.GetRegister(lcd regAddressreadByteLength); lcd.SetRegister(lcdregAddresstxDatalength);
4、应用总结 我们通过实测驱动迪文触摸屏的操作结果与预期一致。我们让MCU给显示屏发送一些数据并在屏上显示出来 再来看看对传感器做一下扰动时用配气仪和小型气泵向传感器管道送不同的气数据的变化传感器检测对象变化是屏幕显示也变化。 再来改变一下气体成分和气泵的转速看看数据的变化 经过以上实验迪文串口屏驱动已经达到预期。至于一些更复杂的操作方式也都可以以此为基础实现之。
欢迎关注