博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一招搞定——结构体、共用体和枚举
阅读量:558 次
发布时间:2019-03-09

本文共 3004 字,大约阅读时间需要 10 分钟。

这是之前学51单片机时的笔记,最近翻到了就发出来啦

一、结构体:

1.其实就是将一堆变量进行封装。如下例(电机结构体)

该结构体将 motor_id、dir、pwm…等变量封装在一个结构体里。

typedef struct MotorPID_s

{
    float Kp,Ki,Kd;

}MotorPID_t;

struct motor_info_t

{

    uint8_t     motor_id;                  //电机ID

    uint8_t     dir;                            //运动方向

    uint16_t    pwm;                       //pwm

    uint8_t     state;                        //运行状态

    uint16_t    encoder;                  //编码器值

    float       f_set_spd;                   //设定速度

    float       f_mea_spd;                 //反馈速度

    ........

    MotorPID_t  p_pid_parm;    //pid结构体 (需要知道结构体里可以包含结构体)

};

SUM:

(1)构体主要作用是封装变量;

(2)定义结构体变量时可以一次性定义多个:如 struct motor_info_t motor_info_t  ,struct motor_info_t  motor_info_table[2];表示定义了2个电机结构体变量;

(3)需要了解  结构体在内存中如何储存以及结构体的字节对齐 。

(补一嘴命名法,匈牙利命名法命名变量时写成由首字母大写的简单词汇连接而成(如CarState,.....)。在linux内核中,_s后缀表示struct(一个结构体) , _t表示一个type(一个类型),如MotorPID_s,MotorPID_t,......)

 

2.做led时有调节频率调节占空比可以这样写

(1)结构体定义:

struct led_info_t

{

    uint8_t     led_duty;                    //led 占空比

    uint8_t     led_freq;                  // led 频率

};

(2)定义结构体变量:

struct led_info_t led;

(3)定义结构体变量赋值:

    led. led_duty = 40;  

    led. led_ freq = 1000;

以上将led的相关变量封装在led_info_t结构体里,可增强代码可读性程序扩展性(假如现在8个灯每个灯的pwm和占空比都不一样,按照原来的方法得定义8*2=16个变量,现在用结构体只需要led_info_t led[8]就好了)

 

3.关于字节对齐:

(1)我们平时写的struct默认是自动字节对齐的,可以手动对齐,将数据按从小到大的顺序排列,尽量凑齐;

(2).使用#pragma pack (n)来指定数据结构的对齐值;

(3)使用 __attribute__ ((packed)) ,让编译器取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。

eg:

struct __attribute__ ((__packed__))motor_pwm            //取消字节对齐

{

    int a;

    u8 b;

}

显然u8和int型变量在内存中所占字节不同,只是b其有效位是低8位,高8位是空位(在51单片机中),而a高8位 低8位都有效。

而若我们没有取消字节对齐那么高8位则是不确定的值,当我们用此结构体中变量进行数据传输(例如通信)而没有取消字节对齐时,常常会传输数据不准确

 

二、共用体(也叫联合体)

1.共用体的所有成员占用同一段内存修改一个成员会影响其余所有成员

举例:

union data_union_u

{

    uint32_t    u32_data;         //无符号32位

    float          f32_data;          //float 32位

    uint8_t      buf[4];              //4个uint8_t 总共4*8=32位

};

以上共用体data_union_u中 u32_data、f32_data 、buf[4] 都是32位共用一个内存。修改任意一个成员都会影响其余所有成员的值。

以上共用体可用于串口传输:因为一般单片机(如51、32)串口一次只能发送8位数据,假如现在要发送一个32位数据就得把32位数据拆分成4个8位数据。

eg:双机通信时因为寄存器每次只能传输八位(32单片机里叫DR寄存器),如果我们想要传输一个浮点型变量可以定义一个共用体,具体如下:

假设我们想传输的值是PI=3.1415926

union data_set{

    float a;

    uint8_t b[4];

}

这样通信的时候用b[4],真正读取数据时用变量a,简单方便又好用。

2.之前用51单片机做定时器时由于定时器是16位,即有高八位第八位(如TH1 TL1)

你可以这样优化

共用体定义:

union data_union_u

{

    uint16_t    u16_data;         //无符号16位

    uint8_t     buf[2];              //2个uint8_t 总共2*8=16位

};

创建共用体变量:

 union data_union_u timer_1;

假如现在定时器1要装载的值是45872, 我们可以 timer_1. u16_data = 45872;

装载TH1和TL1只需要

    TH1 = timer_1. buf[1];

    TL1 = timer_1. buf[0];

取代之前的

    TH1=(65535-45872)/256;

    TL1=(65535-45872)%256;

 

三、枚举:

之前做过最后一个单片机工程:按键控制数码管 上下左右

当时我写的是:

#define key_left   0

#define key_right  1

#define key_up   2

#define key_down 3

可直接优化成枚举如下

定义枚举:

enum key_status_m {                  

    key_left   =   0,

    key_right  =  1,

    key_up   =    2,

    key_down = 3

};                                                               

定义枚举变量:

enum key_status_m key_status;

具体代码里使用 key_status = key_left 对key_status赋值(赋的值只能是定义的0123 如果赋值key_status =4会报错)

switch(key_status)

{

       case: key_left:

       case:key_right:

    ……

}

 

而三者可以相互嵌套使用:

typedef struct Wheel_s

{
    float V_wheel;                //轮子速度
    float wheel_distance;     //轮子所走路程

}Wheel_t;

//轮子所需数据

typedef enum

{
    Wheel_1=0,
    Wheel_2,
    Wheel_3,
    Wheel_4,
    Wheel_sum,

}Wheel_e;

//轮子命名

typedef struct Car_s

{
    Wheel_t Wheel[Wheel_sum];   //结构体嵌套结构体

}Car_t;

//小车整体结构体

Car_t CAR;

 

BUT当然不是嵌套的越多越好,优秀的代码是要简洁和易懂两个方面都出色的,上面这些代码是因为在使用的时候大大减少了我的代码工作量才会使用多重嵌套,如果不能相对简洁代码那使用多重嵌套就是得不偿失,大大减少了可读性。

 

转载地址:http://ljapz.baihongyu.com/

你可能感兴趣的文章