C--->内存操作的相关函数(附加Canopen 协议应用介绍)

| 大纲

  • 内存操作函数介绍:

1.memcpy (memory copy)             <string.h>       复制一个变量的值给两一个变量

2.memcmp(memory compare)      <string.h>        比较两个变量的值是否相同

3.memset(memory set)                  <string.h>       初始化相关变量

4.malloc(memory allocation)          <stdlib.h>       为指针分配内存大小

5.realloc(reset allocation)          <stdlib.h>       扩展指针的内存大小

  • void*用法
  • 应用:  CANopen协议栈的建立

 

1.memcpy

     void* memcpy(void* destiny,void*source,unsigned  length);

      \brief:拷贝source中前 length的字节到destiny中。

      \para:destiny:复制的对象。

                  source:被复制的对象。 

                 length:字节的长度

      \retval: 返回 destiny 的地址

注:在实践中我发现    memcpy(&a[ 0 ] , &b[ 0 ] , LEN),只要数组比较大,LEN可以是无限长,

       如len是3,则 拷贝   a[0] = b[0] 、a[1] = b[1] 、 a[2] =b [2]  ;

应用:常常用于通讯中数据的收发,如在CAN总线中收发报文,接收和发送都使用同一个数组

把数据拷贝到相应的变量中实现内存块的复制,为什么要复制,因为接受到消息接受的是一个局

部变量,我们想要实现收发,就要把变量发到公共的全局变量之中。


2.memset

extern void *memset(void *buffer,   int c,   int count);

常常用于结构体或数组的初始化,如在嵌入式行业中,对GPIO等外设参数进行初始化操作

fg1:

struct vary

{

      uint8_t   a;

      uint16_t b;

      uint32_t c;

}vary1;

memset(&vary1 , 0l, sizeof(vary1));     // 表示对结构体vary1的所有内存块进行清零操作。


3.memcmp

       int memcmp  (void* desiny  ,  void*source,   unsigned char length);

      \brief:比较数据是否相同

      \para:destiny 和source 都是比较对象, length表示比较的字节的长度

      \retval: 相同返回0,destiny>source ,不同:大于0的数;  destiny<source   小于0的数

实际应用:在进行CAN总线通讯时候,CANopen协议层角度,当然节点工作在工作模式heartbeat.buf[0]=0x05,

从机PDO工作在事件触发模式下(event trigger),配合禁止时间(inhibit time),如果数据发生变化就会发送

TPDO报文到上位机,从机如何知道自己数据变化,就是比较原先的数据和现在的数据是否变化。

首先上机节点工作在工作模式(0x05),对TPDO进行初始化拷贝赋值,这个时候记录时间和事件的时间戳。

直接判断时间模式中时间是否到,和事件模式中时间有没有到。一个轮回后,第二次进行模式时候首先判断

数据是否产生变化,然后再判断时间有没有变化。以及考虑时间模式触发下后,需要将所有模式的时间戳重新

更新,并将事件模式的禁止时间重新更新。

       以上谈到多变量问题,这个在设计TPDO结构体的时候就需要考虑到。

4.malloc

       void* malloc(size_t size);

      \brief:为指定变量分配内存空间,并返回一个指向它的指针。

      \para:size是内存块大小,以字节为单位。

      \retval: 返回一个指针,指向已经分配大小的内存。如果请求失败,则返回NULL.

fg1:

int *a =(char*) malloc(10);      //指针指向一个内存为10个字节的地址。


 5.realloc(动态内存调整)

         extern void *realloc(void *mem_address, unsigned int newsize);

       \brief:改变内存大小的指针

       \para:

                mem_address要改变内存大小的指针名

                newsize         给该指针分配新的内存空间的大小

      \retval: 如果重新分配成功,则返回指向被分配内存的指针,否则返回空指针NULL

 fg1:

 

#include <stdio.h>     //输入输出打印库 
#include <string.h>    //字符串库 
#include <stdlib.h>    //标准库 
 
int main()
{
   char *str;    //定义一个指针
 
   /* 最初的内存分配 */
   str = (char *) malloc(15);   //为该指针分配内存 
   strcpy(str, "runoob");       //通过字符串拷贝函数将数据拷贝到相应的指针中 
   printf("String = %s,  Address = %u\n", str, str);
 
   /* 重新分配内存 */
   str = (char *) realloc(str, 25);
   strcat(str, ".com");
   printf("String = %s,  Address = %u\n", str, str);
 
   free(str);                  //释放堆区内存 
 
   return(0);
}

 

结果:

        

 

void*用法

      Void*表示空类型指针,表示任意类型的指针

      对于C/c++而言,是静态类型的语言,定义变量就会分配内存,但不同类型所占内存空间不同。但所有

指针类型的变量,无论是int*、char*、string*等,其内存空间是相同的,指针的本质是存放变量的地址。

方式:

1.向函数传递void*指针

2.从函数返回void*指针

注意点:void*表示任意类型的指针,主要运用内存操作函数的形参类型和返回值类型
注:内存操作与内存中数据类型无关,即任意类型都可以!!!

应用:  CANopen协议栈的建立

//伪代码

CANOPEN_processstack
{
    if(启动标志)
    {
        if(心跳节点.buff[0]==0x00) 
        {
        //1.记录心跳时间戳=心跳时间+设备地址偏移+系统滴答;
        //2.发送心跳包
        成功继续
        不成功return 1; 
        }
        3、选择启动模式
        3.1启动
        心跳节点.buff[0]=0x05;
        TPDO初始化,配置相应的时间戳,状态标志位,以及要发送的信息到buf中
        3.2预先启动
        心跳节点.buff[0]=0x7f;    
    } 
    
    //TPDO有两种工作模式
    //1.inhibit mode  事件触发方式,数据发生变化,并且发送的时间间隔有限制 
    //2.event time  时间触发,时间到就发送消息 
    
    //1.event time mode
        1.判断时间到没到
        2.到了就发送消息,并且将所有模式的时间置位,并设置标志位,防止禁止时间限制
    //2.inhibit time mode
        1.第一次的时候判断时间到没到,到了就发送(第一次数据是新的)
        2.以后每次都判断数据是否变化,
        //这里用到memcmp进行数据块的比较 
        3.如果发生变化,就拷贝数据给TPDO.buf中,然后发送报文 
    
    //心跳模式     
    1.判断心跳是否工作在0x05状态
    2.判断心跳时间是否超出 
    3.发送报文
    4.更新心跳报文的时间戳 
    
    return 1; 
    } 
}
 } 

 

 

时间:2021-11-05  20:55:56 

修改:2021-11-07   / 2022-11-19

 

posted @ 2021-11-05 20:57  InitForever  阅读(240)  评论(0)    收藏  举报