C语言在嵌入式中的应用

前言

在嵌入式设备的编程中,C语言是使用最多最频繁的语言了。所以此篇文档

宏定义

用于条件编译以及增加程序移植性(如:自定义单片机GPIO的别名)

比如:条件编译

#ifndef __STM32F4xx_HAL_GPIO_H
#define __STM32F4xx_HAL_GPIO_H
 /*代码...*/
#endif

比如:给GPIO定义别名增加程序移植性 

#define LED3_PIN                                GPIO_PIN_13
#define LED3_GPIO_PORT                          GPIOG

typedef

说明:用于定义新的变量。比如定义uint8_t、uint16_t等新的数据类型

比如:定义新的数据类型:

/* exact-width signed integer types */
typedef   signed          char int8_t;
typedef   signed short     int int16_t;
typedef   signed           int int32_t;
typedef   signed       __INT64 int64_t;

/* exact-width unsigned integer types */
typedef unsigned          char uint8_t;
typedef unsigned short     int uint16_t;
typedef unsigned           int uint32_t;
typedef unsigned       __INT64 uint64_t;

比如:定义GPIO这个新的数据类型的

typedef struct
{
  __IO uint32_t MODER;    /*!< GPIO port mode register,               Address offset: 0x00      */
  __IO uint32_t OTYPER;   /*!< GPIO port output type register,        Address offset: 0x04      */
  __IO uint32_t OSPEEDR;  /*!< GPIO port output speed register,       Address offset: 0x08      */
  __IO uint32_t PUPDR;    /*!< GPIO port pull-up/pull-down register,  Address offset: 0x0C      */
  __IO uint32_t IDR;      /*!< GPIO port input data register,         Address offset: 0x10      */
  __IO uint32_t ODR;      /*!< GPIO port output data register,        Address offset: 0x14      */
  __IO uint32_t BSRR;     /*!< GPIO port bit set/reset register,      Address offset: 0x18      */
  __IO uint32_t LCKR;     /*!< GPIO port configuration lock register, Address offset: 0x1C      */
  __IO uint32_t AFR[2];   /*!< GPIO alternate function registers,     Address offset: 0x20-0x24 */
} GPIO_TypeDef;

 enum

用来定义一些状态标志以及几个固定的选择参数。比如:ON(开)、OFF(关);IO时钟频率(10MHZ、20MHZ、50HZ等)

typedef enum
{
  GPIO_PIN_RESET = 0,
  GPIO_PIN_SET
}GPIO_PinState;

共用体

所有的成员变量共用同一块内存区域。所以使用共用体主要是为了节省内存空间。

//定义位
typedef union { 
  unsigned char BYTE;			//可以按字节寻址 
  struct { 
    unsigned char BIT0        :1;                                        
    unsigned char BIT1        :1;                                        
    unsigned char BIT2        :1;                                        
    unsigned char BIT3        :1;                                       
    unsigned char BIT4        :1;                                      
    unsigned char BIT5        :1;                                        
    unsigned char BIT6        :1;                                       
    unsigned char BIT7        :1;                                     
  } BIT;						//定义一个只能按位域寻址的新变量类型                                         
} BITFIELD;						//定义一个既能按位域寻址也可按字节寻址的新变量类型

结构体

结构体相当于一个数据的集合,它可以包含所有的基本数据类型。所以它常被用于定义一组数据(包含多种数据类型的)。

注:结构体中成员变量内存也是连续的

typedef struct
{
  __IO uint32_t MODER;    /*!< GPIO port mode register,               Address offset: 0x00      */
  __IO uint32_t OTYPER;   /*!< GPIO port output type register,        Address offset: 0x04      */
  __IO uint32_t OSPEEDR;  /*!< GPIO port output speed register,       Address offset: 0x08      */
  __IO uint32_t PUPDR;    /*!< GPIO port pull-up/pull-down register,  Address offset: 0x0C      */
  __IO uint32_t IDR;      /*!< GPIO port input data register,         Address offset: 0x10      */
  __IO uint32_t ODR;      /*!< GPIO port output data register,        Address offset: 0x14      */
  __IO uint32_t BSRR;     /*!< GPIO port bit set/reset register,      Address offset: 0x18      */
  __IO uint32_t LCKR;     /*!< GPIO port configuration lock register, Address offset: 0x1C      */
  __IO uint32_t AFR[2];   /*!< GPIO alternate function registers,     Address offset: 0x20-0x24 */
} GPIO_TypeDef;

结构体位域

常用于通信协议处理。因为通信协议整个协议占用了多个完整的字节,但是其中很多标志位只占用了一个字节中的某几位,而结构体中的位域就可以解决只用某几位的情况。

//SOF帧的可变区域+标准版本号
typedef struct sof_expand_area{
    uint32_t src_tei: 12;   //源TEI     12位
    uint32_t dec_tei: 12;   //目的TEI    12位
    uint32_t link_flag: 8;  //链路标识符    8位
    uint16_t frame_len: 12; //帧长        12位
    uint16_t phy_num: 4;    //物理块个数
    uint32_t symbol_num: 9; //符号数
    uint32_t bdcast_flag: 1;//广播标志位
    uint32_t retrans_falg: 1; //重传标志位
    uint32_t remain_na: 1;//保留
    uint32_t set_cpy_b_mode: 4;//集拷贝基本模式
    uint32_t set_cpy_expd_mode: 4;//集拷贝扩展模式
    uint32_t stdard_v_num: 4;   //标准版本号
}SOF_EXPAND_AREA;

数组

用于处理连续的内存数据。比如:储存字符串

uint8_t aTxBuffer[] = " **** UART_TwoBoards_ComPolling **** ";

指针

1. 函数形参:在函数中用作形参,可以用来获取数据且可以避免使用返回值来获取数据导致的数据正确性的问题(有个默认值,当没有数据产生时也会返回)

uint8_t readRingbuffer(uint8_t *buffer, uint32_t len)
{
    if (pHead == NULL)
        return 1;


    if (validLen == 0) //空缓冲区
        return 0;

    if (len > validLen) //读取长度大于可用长度
        len = validLen;

    if (pValid + len > pTail) //需要分成两段copy
    {
        uint32_t len1 = pTail - pValid;
        uint32_t len2 = len - len1;
        memcpy(buffer, pValid, len1);       //第一段
        memcpy(buffer + len1, pHead, len2); //第二段,绕到整个存储区的开头
        pValid = pHead + len2;              //更新已使用缓冲区的起始
    }
    else
    {
        memcpy(buffer, pValid, len);
        pValid = pValid + len; //更新已使用缓冲区的起始
    }
    validLen -= len; //更新已使用缓冲区的长度

    return len;
}

2. 普通变量:用作普通变量,方便操作连续的地址。比如:操作数组、字符串等

void CopyStr(char *src,char *des)
{
     while(*src != '\0')
    {
        *des++ = *src++;
    }
}

char arr[8] = "1234567";
char *p = NULL;
p = malloc(sizeof(arr) / sizeof(char));
CopyStr(arr,p);

3. 函数指针:用来更方便灵活的调用函数。比如:回调函数

ARM_DRIVER_VERSION     (*GetVersion)      (void); 

4. 与结构体并用:用于创建链表等数据结构

typedef struct list_node{
    struct list_node *next;
    uint8_t buf_data;
}LIST_NODE;

5. 函数指针与结构体并用:用于实现程序框架的接口

typedef struct _ARM_DRIVER_USART {
  ARM_DRIVER_VERSION     (*GetVersion)      (void);                              ///< Pointer to \ref ARM_USART_GetVersion : Get driver version.
  ARM_USART_CAPABILITIES (*GetCapabilities) (void);                              ///< Pointer to \ref ARM_USART_GetCapabilities : Get driver capabilities.
  int32_t                (*Initialize)      (ARM_USART_SignalEvent_t cb_event);  ///< Pointer to \ref ARM_USART_Initialize : Initialize USART Interface.
  int32_t                (*Uninitialize)    (void);                              ///< Pointer to \ref ARM_USART_Uninitialize : De-initialize USART Interface.
  int32_t                (*PowerControl)    (ARM_POWER_STATE state);             ///< Pointer to \ref ARM_USART_PowerControl : Control USART Interface Power.
  int32_t                (*Send)            (const void *data, uint32_t num);    ///< Pointer to \ref ARM_USART_Send : Start sending data to USART transmitter.
  int32_t                (*Receive)         (      void *data, uint32_t num);    ///< Pointer to \ref ARM_USART_Receive : Start receiving data from USART receiver.
  int32_t                (*Transfer)        (const void *data_out,
                                                   void *data_in,
                                             uint32_t    num);                   ///< Pointer to \ref ARM_USART_Transfer : Start sending/receiving data to/from USART.
  uint32_t               (*GetTxCount)      (void);                              ///< Pointer to \ref ARM_USART_GetTxCount : Get transmitted data count.
  uint32_t               (*GetRxCount)      (void);                              ///< Pointer to \ref ARM_USART_GetRxCount : Get received data count.
  int32_t                (*Control)         (uint32_t control, uint32_t arg);    ///< Pointer to \ref ARM_USART_Control : Control USART Interface.
  ARM_USART_STATUS       (*GetStatus)       (void);                              ///< Pointer to \ref ARM_USART_GetStatus : Get USART status.
  int32_t                (*SetModemControl) (ARM_USART_MODEM_CONTROL control);   ///< Pointer to \ref ARM_USART_SetModemControl : Set USART Modem Control line state.
  ARM_USART_MODEM_STATUS (*GetModemStatus)  (void);                              ///< Pointer to \ref ARM_USART_GetModemStatus : Get USART Modem Status lines state.
} const ARM_DRIVER_USART;

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值