当前位置:网站首页>C# 结构使用
C# 结构使用
2022-07-28 11:40:00 【yi_tianchou】
上位机(C#)需要和单片机通过串口传输数据,本人也是踩了几个坑之后才将该功能实现,时间比较匆忙,写的潦草,有不清楚的可以追问。
单片机上已经定义好了接口和数据格式(结构)
上位机上处理方法:
1、串口接收到byte数组,从数组中按下标获取
如果数据结构单一这个方法未尝不可,如果数据结构较多,结构体较大 那么需要认真的计算下标,否则很容易出现问题,且不易维护。
例如:
private void sp_DataReceived(object sender, EventArgs e)
{
SerialPort sp1 = (SerialPort)sender;
if (sp1.IsOpen) //判断是否打开串口
{
try
{
if (this.InvokeRequired) //加线程防止假死
{
this.Invoke(new MethodInvoker(delegate
{
int int_len = sp1.BytesToRead;
byte[] b = new byte[sp1.BytesToRead];
sp1.Read(b, 0, b.Length); //字节
myBuffer.AddRange(b);
while (myBuffer.Count >= 15)//至少等于报文头长度
{
if (myBuffer[0] == 0xf9 && Array.IndexOf(CMDS, myBuffer[1]) >= 0)
{
int strLen = (myBuffer[2] << 8) + myBuffer[3]+6;
if (strLen > myBuffer.Count)
{
break;
}
int cmpType = (myBuffer[5] << 8) + myBuffer[6];
switch (cmpType)
{
case 0x0B11:
sp.DiscardInBuffer();
sp.DiscardOutBuffer();
myBuffer.RemoveRange(0, myBuffer.Count);
break;
default:
break;
}
myBuffer.RemoveRange(0, myBuffer.Count);
}
else
{
myBuffer.RemoveRange(0, 1);
}
}
}));
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}方法2 将单片机上的数据结构定义到 上位机上
1、对应单品机定义一个一样的结构 用于接收数据 (单片机上已定义 #parama pack(1)) 总之 单片机和 上位机上的 pack(x)要一致
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct TEST
{
byte a;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 28)]
byte[] b;/
byte c;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 28)]
char[] d;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 200)]
string e;// 单片机上定义的长度是多少
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)]
string login_data;//
}注意事项: 1、[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] 是结构的对齐方式 ,pack=1 是指结构的对齐方式为1字节。否则默认是4个字节,不指定pack方式,会发现同样的结构体,sizeof(结构)的大小不一样,以至于出现byte数组转结构的时候,数据对应不上,
如果不使用或者 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)] 中UnmanagedType.ByValTStr与结构中元素不对应,使用在使用sizeof的时候会报
Marshal.SizeOf报“不能作为非托管结构进行封送处理;无法计算有意义的大小或偏移量“错误。
2、单片机上字符串使用char[200],定长
c#中结构可以使用string,但是也要定长(定长使用UnmanagedType.ByValTStr),定长的方法
//
// 摘要:
// 用于在结构中出现的内联定长字符数组。char 类型用于 System.Runtime.InteropServices.UnmanagedType.ByValTStr
// 取决于 System.Runtime.InteropServices.StructLayoutAttribute 属性的 System.Runtime.InteropServices.CharSet
// 参数应用于包含的结构。应始终使用 System.Runtime.InteropServices.MarshalAsAttribute.SizeConst
// 字段来指示数组的大小。
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 200)]
string e;// 单片机上定义的长度是多少
单片机上字符串使用unsigned char[28],定长且UnmanagedType.ByValArray, 用于存储 非字符串的数组
//
// 摘要:
// 当 System.Runtime.InteropServices.MarshalAsAttribute.Value 属性设置为 ByValArray时,必须设置
// System.Runtime.InteropServices.MarshalAsAttribute.SizeConst 字段指示元素数。数组的。当需要区分字符串类型时,System.Runtime.InteropServices.MarshalAsAttribute.ArraySubType
// 字段可以选择包含数组元素的 System.Runtime.InteropServices.UnmanagedType。可以使用此仅 System.Runtime.InteropServices.UnmanagedType
// 数组中元素的形式出现在结构中的字段的属性。
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 28)]
char[] d;
结构体和数组互转://伪代码
public TESTtest= new TEST();
数组转结构:
List<byte> myBuffer = new List<byte>();
private void sp_DataReceived(object sender, EventArgs e)
{
SerialPort sp1 = (SerialPort)sender;
if (sp1.IsOpen) //判断是否打开串口
{
try
{
if (this.InvokeRequired) //加线程防止假死
{
this.Invoke(new MethodInvoker(delegate
{
// Thread.Sleep(20);
int int_len = sp1.BytesToRead;
byte[] b = new byte[sp1.BytesToRead];
sp1.Read(b, 0, b.Length); //字节
myBuffer.AddRange(b);
while (myBuffer.Count >= sizeof(TEST))//至少等于报文长度
{
try
{
test= (TEST)BytesToStruct(myBuffer.ToArray(), typeof(TEST));
}catch()
{
myBuffer.RemoveRange(0, 1);
}
}
myBuffer.RemoveRange(0, myBuffer.Count);
}
}
}));
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}结构转数组:
byte[] s = StructToBytes(test);
转换方法:
/// <summary>
/// 结构体转化成byte[]
/// </summary>
/// <param name="structure"></param>
/// <returns></returns>
public static Byte[] StructToBytes(Object structure)
{
Int32 size = Marshal.SizeOf(structure);
IntPtr buffer = Marshal.AllocHGlobal(size);
try
{
Marshal.StructureToPtr(structure, buffer, false);
Byte[] bytes = new Byte[size];
Marshal.Copy(buffer, bytes, 0, size);
return bytes;
}
finally
{
Marshal.FreeHGlobal(buffer);
}
}
/// <summary>
/// byte[]转化成结构体
/// </summary>
/// <param name="bytes"></param>
/// <param name="strcutType"></param>
/// <returns></returns>
public static Object BytesToStruct(Byte[] bytes, Type strcutType)
{
Int32 size = Marshal.SizeOf(strcutType);
IntPtr buffer = Marshal.AllocHGlobal(size);
try
{
Marshal.Copy(bytes, 0, buffer, size);
return Marshal.PtrToStructure(buffer, strcutType);
}
finally
{
Marshal.FreeHGlobal(buffer);
}
}
声明:转换方法是摘自热心网友的,追究可删
边栏推荐
- Developing NES games with C language (cc65) 04. Complete background
- New Oriental's single quarter revenue was 524million US dollars, a year-on-year decrease of 56.8%, and 925 learning centers were reduced
- HC-05蓝牙模块调试从模式和主模式经历
- Latex matrix is simple to use
- 聚变云原生,赋能新里程 | 2022 开放原子全球开源峰会云原生分论坛圆满召开
- Developing NES games with C language (cc65) 08. Background collision
- Open source huizhichuang future | 2022 open atom global open source summit openatom openeuler sub forum was successfully held
- Introduction to several methods of keeping two decimal places in PHP
- 产学研用 共建开源人才生态 | 2022 开放原子全球开源峰会教育分论坛圆满召开
- [Nuxt 3] (十二) 项目目录结构 3
猜你喜欢

On Governance and innovation | the openanolis sub forum of the 2022 open atom global open source summit was successfully held

开源社区三十年 | 2022 开放原子全球开源峰会开源社区三十年专题活动圆满召开

用C语言开发NES游戏(CC65)09、滚动

设计一个线程池

数字经济时代的开源数据库创新 | 2022 开放原子全球开源峰会数据库分论坛圆满召开

开源汇智创未来 | 2022 开放原子全球开源峰会 OpenAtom openEuler 分论坛圆满召开

Zadig v1.13.0 believes in the power of openness, and workflow connects all values

GMT安装与使用

leetcode:704二分查找

Open source database innovation in the era of digital economy | the 2022 open atom global open source summit database sub forum was successfully held
随机推荐
Cache of laravel
要想组建敏捷团队,这些方法不可少
What SaaS architecture design does a software architect need to know?
Not optimistic about Apple making AR, Luo Yonghao: I'll do it myself
Zadig v1.13.0 believes in the power of openness, and workflow connects all values
Tencent two sides: @bean and @component are used in the same class, what will happen?
PHP timestamp subtraction converts to days, hours, minutes and seconds
Is it difficult for cloud native machine learning to land? Lingqueyun helps enterprises quickly apply mlops
MSP430 开发中遇到的坑(待续)
Develop NES game (cc65) 07 and controller with C language (collision with spirit)
云原生机器学习落地难?灵雀云助力企业快速应用 MLOps
Is it overtime to be on duty? Take up legal weapons to protect your legitimate rights and interests. It's time to rectify the working environment
AVL树(平衡搜索树)
用C语言开发NES游戏(CC65)07、控制器(和精灵碰撞)
用C语言开发NES游戏(CC65)07、控制器
PHP gets all the dates of this week or the last seven days
GMT installation and use
用C语言开发NES游戏(CC65)10、游戏循环
Marketing play is changeable, and understanding the rules is the key!
Implementation method of mouse hover, click and double click in ue4/5