嵌入式C语言中常量的应用实例
常量,我们都知道,就是数值保持不变的量。
在C语言中,常量一旦初始化了,它的值将在整个程序运行周期内,不允许发生任何变化。常量与变量是相对的,我们实际项目中经常会用到它。
定义常量的两种方式
C语言中主要有两种方式定义常量:一种是define,一种是const。define是宏定义,const是常量限定符。
比如,定义一些通用常量,
#ifndef true#define true(1)#endif#ifndef false#define false(0)#endif#ifndef NULL#define NULL(0)#endif
时间常量
#define TIME_BASE10#define TIME_10MS(10/TIME_BASE)#define TIME_20MS(20/TIME_BASE)#define TIME_30MS(30/TIME_BASE)#define TIME_40MS(40/TIME_BASE)#define TIME_50MS(50/TIME_BASE)#define TIME_60MS(60/TIME_BASE)#define TIME_70MS(70/TIME_BASE)#define TIME_80MS(80/TIME_BASE)#define TIME_100MS (100/TIME_BASE)
电压常量
#define LV_18216#define LV_17204#define LV_16192#define LV_15180#define LV_14168#define LV_13156#define LV_12144#define LV_11132#define LV_10120#define LV_9 108#define LV_8 96
以上都是用的define,有人会说用const更好。比如,
const bool true = 1;const bool false = 0;
理由是,const这种定义方式如果出现错误了,编译器会容易指出错误的具体位置。而不像define这种定义方式,报错都报得不直接,毕竟要考虑宏替换之后的情况。
其实,我觉得还好。在我看来,define就是为了给常数起名字。在实际编程过程中,我们应该尽量避免在程序中出现一些奇怪的数字,因为如果时间久了我们回头再来看这些程序,这些突兀的数字对于我们来说代表什么,很难一时半会弄清楚。
而const更适合定义常量数组,
const t_uint32 C_RM_ID[TOTAL_C_RM] = { C_MID_ICM_TSCO, C_MID_EMS_EEC, C_MID_EMS_CCVS, C_MID_ABM, C_MID_APM, C_MID_TESTER_BCM, C_MID_TESTER_FUN};
特别是比较大的数组,一定要定义常量数组,因为单片机的RAM空间是非常有限的,如果不加const限定,编译器就会将其分配到RAM空间中;只有加上了const,编译器才会将其分配到ROM中。普通单片机的RAM空间是要远远少于其ROM空间的。
还是举个例子,前面我有介绍的高频接收模块ATA5781,关于它的配置信息就有1K的字节,
const uint8_t ATA5781_config_data[1024]={0x32,0x06,0x03,0x68,0xDD,0x72,0x01,0xC7,0x00,0x02,0x00,0x00,0x00,0xD9,0x2C,0x88,0x03,0x40,0x00,0x59,0x01,0x03,0x00,0x10,0x03,0x24,0x40,0x10,0x00,0x85,0xC8,0x00,0x07,0x0C,0x0E,0x0F,0x0E,0x0C,0x09,0x05,0x01,0xFC,0xF7,0xF3,0xEF,0xEB,0xE9,0xE8,0xE9,0xEC,0xF0,0xF7,0x01,0x0D,0x00,0xFF,0xFF,0xFF,0xFF,0x83,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x46,0x00,0x80,0xBF,0xC3,0x14,0x20,0x40,0x00,0x50,0x03,0x60,0x00,0x01,0x00,0x11,0x00,0x21,0x00,0x01,0x00,0x11,0x00,0x21,0x00,0x01,0x00,0x11,0x00,0x21,0x00,0x01,0x00,0x11,0x00,0x21,0x00,0x01,0x02,0x03,0x14,0x86,0x86,0xA5,0xA5,0x46,0x46,0xC8,0x08,0x1F,0x1F,0x1F,0x1F,0x0F,0x0F,0x00,0x07,0x3C,0x10,0x07,0xAF,0x01,0x1B,0x02,0xD8,0x00,0x68,0x00,0x64,0x00,0x90,0x0A,0x08,0x00,0x00,0x51,0x00,0x50,0x10,0x20,0xA9,0xAA,0xAA,0xAA,0xA9,0xAA,0xAA,0xAA,0x87,0x87,0x08,0x08,0xAF,0xAF,0x0F,0x0F,0xD3,0xC9,0xB2,0xB5,0x00,0x00,0x96,0x06,0x3B,0x01,0x2F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,......};
有的单片机总共才2k的RAM空间,如果不加const,你这一个数组就占用去了一半。其他的程序整个挤在剩下的空间里,除开其他变量不说,还有堆栈什么的,肯定不够用了。
const更多的是提供锁保护功能,除了像上面这些在定义中“锁变量”,还可以在函数中“锁参数”。
uint8 CAN_TxBufConfig(const CAN_TX_CFG *txConfig) { uint8 result = CAN_FAIL; /* Write TX CMD Register */ CY_SET_REG32(CAN_TX_CMD_PTR(txConfig->txmailbox), (txConfig->txcmd | CAN_TX_WPN_SET)); if ((CY_GET_REG32(CAN_TX_CMD_PTR(txConfig->txmailbox)) & CAN_TX_READ_BACK_MASK) == (txConfig->txcmd & CAN_TX_WPN_CLEAR)) { /* Write TX ID Register */ CY_SET_REG32(CAN_TX_ID_PTR(txConfig->txmailbox), txConfig->txid); if (CY_GET_REG32(CAN_TX_ID_PTR(txConfig->txmailbox)) == txConfig->txid) { result = CYRET_SUCCESS; } } return (result);}
const在这里例子中,实际上就保护了CAN发送的配置不会被篡改。
小结
在常量定义中,define只适合给常量命名,const则适合更复杂的常量结构的定义,还能实现锁保护的功能。