【嵌入式模块芯片开发】DWIN的T5L _DGUS应用开发 显示屏的基本图形显示以及串口命令的动态数据波形功能实现

news2024/11/16 0:18:29

【嵌入式模块芯片开发】DWIN的T5L _DGUS应用开发 显示屏的基本图形显示以及串口命令的动态数据波形功能实现

T5L _DGUS应用在DWIN的各类显示屏中 如DMG80480T070_05WTR等等
可用DWIN官方工具生成一系列上位机显示控件 通过串口命令进行交互实现显示、触摸等功能
也可以进行C51代码编程 直接操作屏幕

文章目录

  • T5L _DGUS的串口数据结构
  • 显示变量配置
  • 端点连线的解析代码实现
  • 数据的屏幕像素转换与波形绘制
  • 波形旧数据后移、新数据固定显示的动态波形实现
  • 完整代码
  • 附录:压缩字符串、大小端格式转换
    • 压缩字符串
      • 浮点数
      • 压缩Packed-ASCII字符串
    • 大小端转换
      • 什么是大端和小端
      • 数据传输中的大小端
      • 总结
      • 大小端转换函数

T5L _DGUS的串口数据结构

参考资料:

《基于T5L ASIC的串口指令屏开发指南Ver1.4》
基于T5L ASIC 的串口指令屏(TA),主要特点包括:
(1)基于 T5L 双核 CPU,GUI 和OS核均运行在200MHz主频,功耗极低。
(224bit 真彩色显示,最大分辨率支持19201080。
(316Mbytes 低成本SPI Flash,JPEG 图片、图标压缩存储,可以指定背景图片存储空间大小。
(4)SD/SDHC 接口下载和配置。
(5)支持置点、连线、区域填充等基本绘图操作。
(6)支持文本、图标、图片、二维码等基本UI显示。
(7)图片或图标按照UI的分辨率设计,不需要处理成和屏的物理分辨率一致。
比如,把分辨率800480 的横屏竖用,设置显示偏转90°,然后图片直接按照480800分辨率设计即可。
(8)电阻触摸屏自动识别误差并动态校正,使用中无需额外校准,避免误操作。
(9)软件接口采用《迪文HMI(工业串口屏)指令集》。
(10)可以开放OS CPU核用于客户二次开发,包括4UARTs、20IOs、1CAN、26* 12bit AD、1PWM、64Kbytes
Flash、320KB RAM。
(11)从M600、K600+、T5UIC2 平台移植到T5L TA指令集平台步骤:
(a)把所有的背景图片放到一个文件夹,使用DGUS3工具软件,处理成一个最大不超过12MB的ICL文件,并
相应编号(图片文件编号从16-48,对应的图片空间从12MB到4MB)。
(b)把需要的字库下载(ASCII 字库如果只用到 1632,那么 0#字库只用到前 2 个字库空间),字库编号超过
24 的,需要注意不要和背景文件占用空间冲突,注意0x98指令相应代码修改。
(c)把图标用DGUS3工具软件压缩成ICL文件,编号00-63放在空余的地方,注意修改0x97指令相应代码。
(d)配置好CFG文件。
(e)用SD卡把这些文件更新到屏里面,注意一定是 断电、插卡、再上电 才能升级。

T5L _DGUS的串口数据基本结构体如下:

//Size=len(CMD+Value_Add+Data)=len(Data)+3      All_Len=Size+3
#pragma pack(1)
typedef struct
{
    uint8_t Head[2];
    uint8_t Size;
    uint8_t CMD;
    uint8_t Value_Add[2];
    uint8_t Data[249];
}T5L_DGUS_Struct;
#pragma pack()

在这里插入图片描述
所有数据均为小端格式

结构体发送函数为:

uint8_t T5L_DGUS_Send(T5L_DGUS_Struct Stu,uint8_t * buf)
{
    memcpy(&buf[0],&Stu,Stu.Size+3);

    uint8_t i=0;
    for(i=0;i<Stu.Size+3;i++)
    {
        printf("%02X ",buf[i]);
    }    
    return 1;
}

这里的printf只是为了方便开发 实际在MCU中 改成专门的串口发送函数

显示变量配置

在T5L _DGUS II 应用开发指南中可以看到显示变量配置功能:

在这里插入图片描述
其中有一个图形变量 下含基本图像显示
在这里插入图片描述
其控件需要再DWIN软件中进行配置
在这里插入图片描述
配置好后 可以通过串口命令进行控制

在这里插入图片描述
这里 我们用到的是端点连线命令 用于进行数据波形的动态显示

端点连线的解析代码实现

端点连续示例如图所示
在这里插入图片描述
端点连线部分结构体:

#pragma pack(1)
typedef struct
{
    uint8_t X[2];
    uint8_t Y[2];
}T5L_DGUS_Base_Graph_Location_Struct;
#pragma pack()

//P2P_Size=len(Location)-1  P2P_Data_Len=8+len(Location)*4=(P2P_Size+1)*4+8
#pragma pack(1)
typedef struct
{
    uint8_t P2P_CMD[2];
    uint8_t P2P_Size[2];
    uint8_t Color[2];
    T5L_DGUS_Base_Graph_Location_Struct Location[15];
    uint8_t End[2];
}T5L_DGUS_Base_Graph_P2P_Data_Struct;
#pragma pack()

P2P_Size是线段数
一条线段需要两个断点才能确定
所以对应的点坐标组数为P2P_Size-1

点坐标类型为uint16_t的X、Y
所以可以定义一个小端格式的坐标转换函数
用于坐标转换
比如:

#pragma pack(1)
typedef struct
{
    uint16_t X;
    uint16_t Y;
}Location_Struct;
#pragma pack()
uint8_t i=0;
    for(i=0;i<P2P_Size+1;i++)
    {
        P2P_Stu.Location[i].X[0]=Location[i].X>>8;
        P2P_Stu.Location[i].X[1]=Location[i].X&0xFF;

        P2P_Stu.Location[i].Y[0]=Location[i].Y>>8;
        P2P_Stu.Location[i].Y[1]=Location[i].Y&0xFF;
    }

完整代码为:

T5L_DGUS_Struct T5L_DGUS_Base_Graph_P2P_Trans(Location_Struct *Location,uint16_t P2P_Size,uint16_t Color)
{
    T5L_DGUS_Struct Stu={T5L_DGUS_Head0,T5L_DGUS_Head1,(P2P_Size+1)*4+11,T5L_DGUS_CMD_Write,T5L_DGUS_Base_Graph_Value_Add0,T5L_DGUS_Base_Graph_Value_Add1};
    T5L_DGUS_Base_Graph_P2P_Data_Struct P2P_Stu={0};

    P2P_Stu.P2P_CMD[0]=T5L_DGUS_Base_Graph_P2P_Data_CMD0;
    P2P_Stu.P2P_CMD[1]=T5L_DGUS_Base_Graph_P2P_Data_CMD1;
    P2P_Stu.P2P_Size[0]=P2P_Size>>8;
    P2P_Stu.P2P_Size[1]=P2P_Size&0xFF;
    
    P2P_Stu.Color[0]=Color>>8;
    P2P_Stu.Color[1]=Color&0xFF;

    P2P_Stu.End[0]=T5L_DGUS_Base_Graph_P2P_Data_End0;
    P2P_Stu.End[1]=T5L_DGUS_Base_Graph_P2P_Data_End1;

    uint8_t i=0;
    for(i=0;i<P2P_Size+1;i++)
    {
        P2P_Stu.Location[i].X[0]=Location[i].X>>8;
        P2P_Stu.Location[i].X[1]=Location[i].X&0xFF;

        P2P_Stu.Location[i].Y[0]=Location[i].Y>>8;
        P2P_Stu.Location[i].Y[1]=Location[i].Y&0xFF;
    }
    
    memcpy(&Stu.Data[0],&P2P_Stu,(P2P_Size+1)*4+6);
    memcpy(&Stu.Data[(P2P_Size+1)*4+6],&P2P_Stu.End[0],2);
    return Stu;
}

数据的屏幕像素转换与波形绘制

我用的屏幕为800*480的
左上角坐标为0 0
我将屏幕横竖都分成10份(对应有11个标识点)
就能同时显示11个数据 每个数据的范围为0-10
数据坐标转换函数为:

//X: 0:100 10:700       X=i*60+100
//Y: 10:40 0:440        Y=440-40.0f*v
Location_Struct Value_to_Location(uint8_t i,float value,float min,float max)
{
    Location_Struct Stu;

    if(i>10){i=10;}

    Stu.X=i*70+50;

    if (value>max){value=max;}
    if (value<min){value=min;}

    Stu.Y=440.0f-400.0f/(max-min)*(value-min);
    
    return Stu;
}

在绘制波形时 可以先将第一个点位与原点连接(或者其他原点) 然后接着连接第2个 一直到第11个
加上原点的话 最多同时显示12个点的坐标
由于每次屏幕执行一个命令时 会将之前绘制的图像重置掉 所以每次增加点的显示都需要将先前的点位和线段累加上去

测试函数如下:

int main()
{
    uint8_t i=0;
    float value[11]={2.2,1.3,5,7,6,9,10,0,5,4.4,5.6};
    uint8_t buf[250];
    Location_Struct Lo_Stu[12];

    Lo_Stu[0].X=0;
    Lo_Stu[0].Y=440;
    for(i=0;i<11;i++)
    {
        Lo_Stu[i+1]=Value_to_Location(i,value[i],0,10);

        T5L_DGUS_Struct Stu=T5L_DGUS_Base_Graph_P2P_Trans(Lo_Stu,i+1,T5L_DGUS_Base_Graph_P2P_Data_Color);
        T5L_DGUS_Send(Stu,buf);
        printf("\n");
  
    }

    return 0;
}

输出结果:

5A A5 13 82 54 40 00 02 00 01 F8 00 00 00 01 B8 00 32 01 60 FF 00 
5A A5 17 82 54 40 00 02 00 02 F8 00 00 00 01 B8 00 32 01 60 00 78 01 84 FF 00 
5A A5 1B 82 54 40 00 02 00 03 F8 00 00 00 01 B8 00 32 01 60 00 78 01 84 00 BE 00 F0 FF 00 
5A A5 1F 82 54 40 00 02 00 04 F8 00 00 00 01 B8 00 32 01 60 00 78 01 84 00 BE 00 F0 01 04 00 A0 FF 00 
5A A5 23 82 54 40 00 02 00 05 F8 00 00 00 01 B8 00 32 01 60 00 78 01 84 00 BE 00 F0 01 04 00 A0 01 4A 00 C8 FF 00 
5A A5 27 82 54 40 00 02 00 06 F8 00 00 00 01 B8 00 32 01 60 00 78 01 84 00 BE 00 F0 01 04 00 A0 01 4A 00 C8 01 90 00 50 FF 00 
5A A5 2B 82 54 40 00 02 00 07 F8 00 00 00 01 B8 00 32 01 60 00 78 01 84 00 BE 00 F0 01 04 00 A0 01 4A 00 C8 01 90 00 50 01 D6 00 28 FF 00 
5A A5 2F 82 54 40 00 02 00 08 F8 00 00 00 01 B8 00 32 01 60 00 78 01 84 00 BE 00 F0 01 04 00 A0 01 4A 00 C8 01 90 00 50 01 D6 00 28 02 1C 01 B8 FF 00 
5A A5 33 82 54 40 00 02 00 09 F8 00 00 00 01 B8 00 32 01 60 00 78 01 84 00 BE 00 F0 01 04 00 A0 01 4A 00 C8 01 90 00 50 01 D6 00 28 02 1C 01 B8 02 62 00 F0 FF 00 
5A A5 37 82 54 40 00 02 00 0A F8 00 00 00 01 B8 00 32 01 60 00 78 01 84 00 BE 00 F0 01 04 00 A0 01 4A 00 C8 01 90 00 50 01 D6 00 28 02 1C 01 B8 02 62 00 F0 02 A8 01 08 FF 00 
5A A5 3B 82 54 40 00 02 00 0B F8 00 00 00 01 B8 00 32 01 60 00 78 01 84 00 BE 00 F0 01 04 00 A0 01 4A 00 C8 01 90 00 50 01 D6 00 28 02 1C 01 B8 02 62 00 F0 02 A8 01 08 02 EE 00 D8 FF 00 

波形动态效果:

https://www.bilibili.com/video/BV1Mf42197KN/

波形旧数据后移、新数据固定显示的动态波形实现

为了更加直观展示新数据 每次获取到数据后 将老的数据波形整体后移

那么就需要在MCU中进行数据保存 且保存至少11组数据
可以做如下操作:

 while(1)
  {
    /* add user code begin 3 */
		i++;
		printf("[INFO] %u\n",i);
			Ctrl_A121_Read();	//读取数据
			
			for(j=0;j<11;j++)
			{				
				T5L_DGUS_Lo_Stu[j].Y=T5L_DGUS_Lo_Stu[j+1].Y;
				if(j==0)
				{
					T5L_DGUS_Lo_Stu[j].X=0;
				}
				else
				{
					T5L_DGUS_Lo_Stu[j].X=T5L_DGUS_Lo_Stu[j+1].X-70;
				}				
			}
			Lo_Stu=T5L_DGUS_Value_to_Location(11,distance,0,10);  //转换新数据
			T5L_DGUS_Lo_Stu[11]=Lo_Stu;			
			T5L_DGUS_Send(T5L_DGUS_Base_Graph_P2P_Trans(T5L_DGUS_Lo_Stu,11,T5L_DGUS_Base_Graph_P2P_Data_Color),&T5L_DGUS_Buf[0]);

			delay_ms(read_time_ms);
		}

完整代码

#include<stdio.h>
#include<stdint.h>
#include<string.h>
#include <stdio.h>
#include <string.h>
#include "T5L_DGUS.h"

T5L_DGUS_Struct T5L_DGUS_Base_Graph_P2P_Trans(Location_Struct *Location,uint16_t P2P_Size,uint16_t Color)
{
    T5L_DGUS_Struct Stu={T5L_DGUS_Head0,T5L_DGUS_Head1,(P2P_Size+1)*4+11,T5L_DGUS_CMD_Write,T5L_DGUS_Base_Graph_Value_Add0,T5L_DGUS_Base_Graph_Value_Add1};
    T5L_DGUS_Base_Graph_P2P_Data_Struct P2P_Stu={0};

    P2P_Stu.P2P_CMD[0]=T5L_DGUS_Base_Graph_P2P_Data_CMD0;
    P2P_Stu.P2P_CMD[1]=T5L_DGUS_Base_Graph_P2P_Data_CMD1;
    P2P_Stu.P2P_Size[0]=P2P_Size>>8;
    P2P_Stu.P2P_Size[1]=P2P_Size&0xFF;
    
    P2P_Stu.Color[0]=Color>>8;
    P2P_Stu.Color[1]=Color&0xFF;

    P2P_Stu.End[0]=T5L_DGUS_Base_Graph_P2P_Data_End0;
    P2P_Stu.End[1]=T5L_DGUS_Base_Graph_P2P_Data_End1;

    uint8_t i=0;
    for(i=0;i<P2P_Size+1;i++)
    {
        P2P_Stu.Location[i].X[0]=Location[i].X>>8;
        P2P_Stu.Location[i].X[1]=Location[i].X&0xFF;

        P2P_Stu.Location[i].Y[0]=Location[i].Y>>8;
        P2P_Stu.Location[i].Y[1]=Location[i].Y&0xFF;
    }
    
    memcpy(&Stu.Data[0],&P2P_Stu,(P2P_Size+1)*4+6);
    memcpy(&Stu.Data[(P2P_Size+1)*4+6],&P2P_Stu.End[0],2);
    return Stu;
}

uint8_t T5L_DGUS_Send(T5L_DGUS_Struct Stu,uint8_t * buf)
{
    memcpy(&buf[0],&Stu,Stu.Size+3);

    uint8_t i=0;
    for(i=0;i<Stu.Size+3;i++)
    {
        printf("%02X ",buf[i]);
    }    
    return 1;
}

//X: 0:100 10:700       X=i*60+100
//Y: 10:40 0:440        Y=440-40.0f*v
Location_Struct Value_to_Location(uint8_t i,float value,float min,float max)
{
    Location_Struct Stu;

    if(i>10){i=10;}

    Stu.X=i*70+50;

    if (value>max){value=max;}
    if (value<min){value=min;}

    Stu.Y=440.0f-400.0f/(max-min)*(value-min);
    
    return Stu;
}

int main()
{
    uint8_t i=0;
    float value[11]={2.2,1.3,5,7,6,9,10,0,5,4.4,5.6};
    uint8_t buf[250];
    Location_Struct Lo_Stu[12];

    Lo_Stu[0].X=0;
    Lo_Stu[0].Y=440;
    for(i=0;i<11;i++)
    {
        Lo_Stu[i+1]=Value_to_Location(i,value[i],0,10);

        T5L_DGUS_Struct Stu=T5L_DGUS_Base_Graph_P2P_Trans(Lo_Stu,i+1,T5L_DGUS_Base_Graph_P2P_Data_Color);
        T5L_DGUS_Send(Stu,buf);
        printf("\n");
  
    }

    return 0;
}

#ifndef _T5L_DGUS_H_
#define _T5L_DGUS_H_
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <string.h>

#define T5L_DGUS_Head           0x5AA5
#define T5L_DGUS_Head0          (uint8_t)(T5L_DGUS_Head>>8)
#define T5L_DGUS_Head1          (uint8_t)(T5L_DGUS_Head&0xFF)

#define T5L_DGUS_CMD_Write      0x82
#define T5L_DGUS_CMD_Read       0x83

#define T5L_DGUS_Base_Graph_Value_Add   0x5440
#define T5L_DGUS_Base_Graph_Value_Add0  (uint8_t)(T5L_DGUS_Base_Graph_Value_Add>>8)
#define T5L_DGUS_Base_Graph_Value_Add1  (uint8_t)(T5L_DGUS_Base_Graph_Value_Add&0xFF)

#define T5L_DGUS_Base_Graph_P2P_Data_CMD    0x0002
#define T5L_DGUS_Base_Graph_P2P_Data_CMD0    (uint8_t)(T5L_DGUS_Base_Graph_P2P_Data_CMD>>8)
#define T5L_DGUS_Base_Graph_P2P_Data_CMD1    (uint8_t)(T5L_DGUS_Base_Graph_P2P_Data_CMD&0xFF)

#define T5L_DGUS_Base_Graph_P2P_Data_Color  0xF800

#define T5L_DGUS_Base_Graph_P2P_Data_End    0xFF00
#define T5L_DGUS_Base_Graph_P2P_Data_End0    (uint8_t)(T5L_DGUS_Base_Graph_P2P_Data_End>>8)
#define T5L_DGUS_Base_Graph_P2P_Data_End1    (uint8_t)(T5L_DGUS_Base_Graph_P2P_Data_End&0xFF)

//Size=len(CMD+Value_Add+Data)=len(Data)+3      All_Len=Size+3
#pragma pack(1)
typedef struct
{
    uint8_t Head[2];
    uint8_t Size;
    uint8_t CMD;
    uint8_t Value_Add[2];
    uint8_t Data[249];
}T5L_DGUS_Struct;
#pragma pack()


#pragma pack(1)
typedef struct
{
    uint16_t X;
    uint16_t Y;
}Location_Struct;
#pragma pack()

#pragma pack(1)
typedef struct
{
    uint8_t X[2];
    uint8_t Y[2];
}T5L_DGUS_Base_Graph_Location_Struct;
#pragma pack()

//P2P_Size=len(Location)-1  P2P_Data_Len=8+len(Location)*4=(P2P_Size+1)*4+8
#pragma pack(1)
typedef struct
{
    uint8_t P2P_CMD[2];
    uint8_t P2P_Size[2];
    uint8_t Color[2];
    T5L_DGUS_Base_Graph_Location_Struct Location[15];
    uint8_t End[2];
}T5L_DGUS_Base_Graph_P2P_Data_Struct;
#pragma pack()

#endif

附录:压缩字符串、大小端格式转换

压缩字符串

首先HART数据格式如下:
在这里插入图片描述
在这里插入图片描述
重点就是浮点数和字符串类型
Latin-1就不说了 基本用不到

浮点数

浮点数里面 如 0x40 80 00 00表示4.0f

在HART协议里面 浮点数是按大端格式发送的 就是高位先发送 低位后发送

发送出来的数组为:40,80,00,00

但在C语言对浮点数的存储中 是按小端格式来存储的 也就是40在高位 00在低位
浮点数:4.0f
地址0x1000对应00
地址0x1001对应00
地址0x1002对应80
地址0x1003对应40

若直接使用memcpy函数 则需要进行大小端转换 否则会存储为:
地址0x1000对应40
地址0x1001对应80
地址0x1002对应00
地址0x1003对应00

大小端转换:

void swap32(void * p)
{
   uint32_t *ptr=p;
   uint32_t x = *ptr;
   x = (x << 16) | (x >> 16);
   x = ((x & 0x00FF00FF) << 8) | ((x >> 8) & 0x00FF00FF);

   *ptr=x;
}

压缩Packed-ASCII字符串

本质上是将原本的ASCII的最高2位去掉 然后拼接起来 比如空格(0x20)
四个空格拼接后就成了
1000 0010 0000 1000 0010 0000
十六进制:82 08 20
对了一下表 0x20之前的识别不了
也就是只能识别0x20-0x5F的ASCII表
在这里插入图片描述

压缩/解压函数后面再写:

//传入的字符串和数字必须提前声明 且字符串大小至少为str_len 数组大小至少为str_len%4*3 str_len必须为4的倍数
uint8_t Trans_ASCII_to_Pack(uint8_t * str,uint8_t * buf,const uint8_t str_len)
{
   if(str_len%4)
   {
      return 0;
   }
	 
   uint8_t i=0;
   memset(buf,0,str_len/4*3);	  
   for(i=0;i<str_len;i++)
   {
      if(str[i]==0x00)
      {
         str[i]=0x20;
      }
   }

   for(i=0;i<str_len/4;i++)
   {
      buf[3*i]=(str[4*i]<<2)|((str[4*i+1]>>4)&0x03);
      buf[3*i+1]=(str[4*i+1]<<4)|((str[4*i+2]>>2)&0x0F);
      buf[3*i+2]=(str[4*i+2]<<6)|(str[4*i+3]&0x3F);
   }

   return 1;
}

//传入的字符串和数字必须提前声明 且字符串大小至少为str_len 数组大小至少为str_len%4*3 str_len必须为4的倍数
uint8_t Trans_Pack_to_ASCII(uint8_t * str,uint8_t * buf,const uint8_t str_len)
{
   if(str_len%4)
   {
      return 0;
   }

   uint8_t i=0;

   memset(str,0,str_len);

   for(i=0;i<str_len/4;i++)
   {
      str[4*i]=(buf[3*i]>>2)&0x3F;
      str[4*i+1]=((buf[3*i]<<4)&0x30)|(buf[3*i+1]>>4);
      str[4*i+2]=((buf[3*i+1]<<2)&0x3C)|(buf[3*i+2]>>6);
      str[4*i+3]=buf[3*i+2]&0x3F;
   }

   return 1;
}


大小端转换

在串口等数据解析中 难免遇到大小端格式问题

什么是大端和小端

所谓的大端模式,就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。

所谓的小端模式,就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。

简单来说:大端——高尾端,小端——低尾端

举个例子,比如数字 0x12 34 56 78在内存中的表示形式为:

1)大端模式:

低地址 -----------------> 高地址

0x12 | 0x34 | 0x56 | 0x78

2)小端模式:

低地址 ------------------> 高地址

0x78 | 0x56 | 0x34 | 0x12

可见,大端模式和字符串的存储模式类似。

数据传输中的大小端

比如地址位、起止位一般都是大端格式
如:
起始位:0x520A
则发送的buf应为{0x52,0x0A}

而数据位一般是小端格式(单字节无大小端之分)
如:
一个16位的数据发送出来为{0x52,0x0A}
则对应的uint16_t类型数为: 0x0A52

而对于浮点数4.0f 转为32位应是:
40 80 00 00

以大端存储来说 发送出来的buf就是依次发送 40 80 00 00

以小端存储来说 则发送 00 00 80 40

由于memcpy等函数 是按字节地址进行复制 其复制的格式为小端格式 所以当数据为小端存储时 不用进行大小端转换
如:

uint32_t dat=0;
uint8_t buf[]={0x00,0x00,0x80,0x40};
   memcpy(&dat,buf,4);
   float f=0.0f;
   f=*((float*)&dat); //地址强转
   printf("%f",f);

或更优解:

   uint8_t buf[]={0x00,0x00,0x80,0x40};   
   float f=0.0f;
   memcpy(&f,buf,4);

而对于大端存储的数据(如HART协议数据 全为大端格式) 其复制的格式仍然为小端格式 所以当数据为小端存储时 要进行大小端转换
如:

uint32_t dat=0;
uint8_t buf[]={0x40,0x80,0x00,0x00};
   memcpy(&dat,buf,4);
   float f=0.0f;
   swap32(&dat); //大小端转换
   f=*((float*)&dat); //地址强转
   printf("%f",f);

或:

uint8_t buf[]={0x40,0x80,0x00,0x00};
   memcpy(&dat,buf,4);
   float f=0.0f;
   swap32(&f); //大小端转换
   printf("%f",f);

或更优解:

uint32_t dat=0;
uint8_t buf[]={0x40,0x80,0x00,0x00};
   float f=0.0f;
   dat=(buf[0]<<24)|(buf[0]<<16)|(buf[0]<<8)|(buf[0]<<0)
   f=*((float*)&dat);

总结

固 若数据为小端格式 则可以直接用memcpy函数进行转换 否则通过移位的方式再进行地址强转

对于多位数据 比如同时传两个浮点数 则可以定义结构体之后进行memcpy复制(数据为小端格式)

对于小端数据 直接用memcpy写入即可 若是浮点数 也不用再进行强转

对于大端数据 如果不嫌麻烦 或想使代码更加简洁(但执行效率会降低) 也可以先用memcpy写入结构体之后再调用大小端转换函数 但这里需要注意的是 结构体必须全为无符号整型 浮点型只能在大小端转换写入之后再次强转 若结构体内采用浮点型 则需要强转两次

所以对于大端数据 推荐通过移位的方式来进行赋值 然后再进行个别数的强转 再往通用结构体进行写入

多个不同变量大小的结构体 要主要字节对齐的问题
可以用#pragma pack(1) 使其对齐为1
但会影响效率

大小端转换函数

直接通过对地址的操作来实现 传入的变量为32位的变量
中间变量ptr是传入变量的地址

void swap16(void * p)
{
   uint16_t *ptr=p;
   uint16_t x = *ptr;
   x = (x << 8) | (x >> 8);

   *ptr=x;
}

void swap32(void * p)
{
   uint32_t *ptr=p;
   uint32_t x = *ptr;
   x = (x << 16) | (x >> 16);
   x = ((x & 0x00FF00FF) << 8) | ((x >> 8) & 0x00FF00FF);

   *ptr=x;
}

void swap64(void * p)
{
   uint64_t *ptr=p;
   uint64_t x = *ptr;
   x = (x << 32) | (x >> 32);
   x = ((x & 0x0000FFFF0000FFFF) << 16) | ((x >> 16) & 0x0000FFFF0000FFFF);
   x = ((x & 0x00FF00FF00FF00FF) << 8) | ((x >> 8) & 0x00FF00FF00FF00FF);

   *ptr=x;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1713009.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【上】王树森《小红书推荐系统公开课》- 课程笔记(推荐系统基础、召回、排序)

写在前面 本文为王树森老师《小红书推荐系统公开课》的课程笔记 课程来源&#xff1a;ShusenWang的个人空间-ShusenWang个人主页-哔哩哔哩视频 (bilibili.com)课程资料&#xff1a;GitHub - wangshusen/RecommenderSystem 由于篇幅较长&#xff0c;分为【上】【下】两篇文章…

HTML静态网页成品作业(HTML+CSS)——动漫海贼王介绍网页(1个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有1个页面。 二、作品演示 三、代…

VSCode 报错 之 运行 js 文件报错 ReferenceError: document is not defined

1. 背景 持续学习ing 2. 遇到的问题 在VSCode 右键 code runner js 文件报错 ReferenceError: document is not defined eg&#xff1a; // 为每个按钮添加点击事件监听器 document.querySelectorAll(button).forEach(function (button) {button.addEventListener(click, f…

全面盘点多模态融合算法及应用场景

关注作者&#xff0c;分享AI全维度知识。作者拥有10年互联网服务架构、AI产品研发经验、团队管理经验&#xff0c;同济本复旦硕博&#xff0c;复旦机器人智能实验室成员&#xff0c;阿里云认证的资深架构师&#xff0c;项目管理专业人士&#xff0c;上亿营收AI产品研发负责人 多…

AI 绘图要如何入门?有哪些好用的软件推荐?(附工具+教程+变现模式)

1.Ai绘画如何入门 不需要把Ai绘画想的很复杂 抛去复杂的应用 使用现成简单的工具 只需要学会提示词 描述你想要的画面即可 提示词 不需要太复杂&#xff0c;也不能太简单&#xff0c;太简单依赖于ai的基本样式&#xff0c;关键是要抓住你想要的核心描述 AI不太擅长理解人类的…

Flask和Django的对比

文章目录 1. 简介FlaskDjango 2. 安装和创建项目FlaskDjango 3. URL路由FlaskDjango 4. 数据库支持FlaskDjango 5. 管理后台FlaskDjango 6. 总结 Flask和Django都是Python Web框架&#xff0c;它们在开发Web应用程序时都能提供强大的功能。本文将对这两个框架进行对比&#xff…

PPT 隐藏开启对象图层

目录预览 一、问题描述二、解决方案三、参考链接 一、问题描述 制作PPT的时候&#xff0c;有时候需要在一张PPT放置多个依次出现的内容&#xff0c;然后设置对应的动画&#xff0c;要是需要对某个内容进行修改的话&#xff0c;就会很不方便&#xff0c;这个时候就需要使用&…

微信小程序上架,AI类目审核(AI问答、AI绘画、AI换脸)

小程序对于生成式AI类目的产品上架审核较为严格&#xff0c;这也是近两年新增了几个类目&#xff0c;一旦小程序中涉及生成式AI相关的内容&#xff0c;如果你选择相应类目&#xff0c;但审核被划归为这一类&#xff0c;都需要准备此类目的审核&#xff0c;才能正常上架。 如果…

淘宝API探秘:一键获取店铺所有商品的魔法之旅

在数字时代的今天&#xff0c;数据已经成为了商业世界中的魔法石。而对于淘宝店主或者那些想要深入探索淘宝数据的人来说&#xff0c;淘宝API就像是打开阿里巴巴宝藏库的钥匙。今天&#xff0c;我们就来一起探索如何使用淘宝API&#xff0c;特别是如何获取店铺所有商品的接口&a…

倩女幽魂手游攻略:新人入坑必看指南!

《倩女幽魂》是一款经典的MMORPG游戏&#xff0c;凭借其丰富的剧情、精美的画面和多样的玩法&#xff0c;吸引了众多玩家。在游戏中&#xff0c;提升角色等级和战斗力是每个玩家的核心目标。本文将详细介绍如何在游戏中快速提升角色等级、增强实力&#xff0c;并提供一些实用的…

MT2076 小码哥处理订单

思路&#xff1a; 使用二分&#xff1a;题目中隐含条件&#xff1a;如果不满足&#xff0c;需要找到第一个不满足的订单。 二分法需要满足单调性or有一个界线使前后两部分性质相反。这里的”界线“为&#xff1a;是否满足条件。假设第i天无法满足&#xff0c;则后面的所有天都…

【跟着例子学MySQL】SQL进阶 – 视图、事务和变量

文章目录 前言回顾视图事务用户变量未完待续 前言 举例子&#xff0c;是最简单有效的学习方法。本系列文章以一个贯穿始终的场景&#xff0c;结合多个实例讲解MySQL的基本用法。 ❔ 为什么要写这个系列&#xff1f; 模仿是最好的老师&#xff0c;实践是检验成果的方法。本系列…

OWASP top10--SQL注入(四、sqlmap安装及使用)

目录 sqlmap工具安装&#xff1a; 工具说明&#xff1a; 主要功能特性包括&#xff1a; 基本使用示例&#xff1a; 先下载python2.7.9版本 sqlmap运行 sqlmap工具使用 -u -r –-levelLEVEL扫描深度级别 --riskRISK 执行测试的风险 -threads 线程数 -batch-smart智能…

【源码】多语言H5聊天室/thinkphp多国语言即时通讯/H5聊天室源码/在线聊天/全开源

多语言聊天室系统&#xff0c;可当即时通讯用&#xff0c;系统默认无需注册即可进入群聊天&#xff0c;全开源 【海外聊天室】多语言H5聊天室/thinkphp多国语言即时通讯/H5聊天室源码/在线聊天/全开源 - 吾爱资源网

Java集合—Set(Collection子接口)及其子类(HashSet、LinkedHashSet)包括HashMap源码分析

Set接口是 Collection接口的子接口。 1、无序&#xff0c;即添加元素和去除元素的顺序不一致。 但是每次取出的顺序是一致的。 2、不允许重复元素&#xff0c;可以有null&#xff0c;但只能有一个。 3、实现类很多&#xff0c;主要介绍HashSet、LinkedHashSet 和 TreeSet。 常用…

四、.Net8对接Ollama实现文字翻译(.Net8+SemanticKernel+Ollama)本地运行自己的大模型

.Net8SemanticKernelOllama 一、Semantic Kernel官方定义SK能做什么&#xff1f; 二、基本使用1、普通对话2、使用插件实现文本翻译功能 三、IChatCompletionService、ITextGenerationService、ITextEmbeddingGenerationService 很多情况都有这样的需求&#xff0c;使用自有系统…

PS系统教学02

多个图片同时进行打开 在素材库里面选中两张图片&#xff0c;直接拖进PS软件中&#xff0c;此时会显示其中一张。当按下回车键会显示另一张。 当图层过多&#xff0c;需要进行选择&#xff0c;其中某一张图片&#xff0c;按住Ctrl键&#xff0c;进行选择点击&#xff0c;可以移…

Windows下切换不同版本的CUDA

在环境变量处将需要使用的CUDA版本的如图所框选的环境变量移到其他版本环境变量的前方即可 PS&#xff1a;改环境变量后重启命令行再查看版本~

【Jmeter】性能测试之压测脚本生成,也可以录制接口自动化测试场景

准备工作-10分中药录制HTTPS脚本&#xff0c;需配置证书 准备工作-10分中药 以https://www.baidu.com/这个地址为录制脚本的示例。 录制脚本前的准备工作当然是得先把Jmeter下载安装好、JDK环境配置好、打开Jmeter.bat&#xff0c;打开cmd&#xff0c;输入ipconfig&#xff0c;…

SpringMVC枚举类型字段处理

在日常的项目开发中经常会遇到一些取值范围固定的字段&#xff0c;例如性别、证件类型、会员等级等&#xff0c;此时我们可以利用枚举来最大程度减少字段的乱定义&#xff0c;统一管理枚举的值。 SpringMVC中对于枚举也有默认的处理策略&#xff1a; 对于RequestParam&#xf…