首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C51 單片機 intrins.h 內部函數詳解與應用指南

     編輯:關於C語言

前言

在 Keil C51 開發環境中,<intrins.h> 頭文件提供了一組映射到 8051 核心指令集的內部函數。這些函數讓 C 語言能直接調用汽編指令,實現高效的位操作、空操作延時、位測試等底層控制,是編寫高性能、精確定時嵌入式代碼的利器。本文詳細解析各函數原型、功能、指令對應關係及實戰示例。

函數速查表

函數名功能對應指令適用類型
_crol_字符循環左移RL Aunsigned char
_cror_字符循環右移RR Aunsigned char
_irol_整數循環左移RL A (16位)unsigned int
_iror_整數循環右移RR A (16位)unsigned int
_lrol_長整數循環左移RL A (32位)unsigned long
_lror_長整數循環右移RR A (32位)unsigned long
_nop_空操作(1機器週期)NOPvoid
_testbit_測試並清零位JBC bit, relbit

詳細函數解析

1. 循環移位函數族

原型

unsigned char _crol_(unsigned char val, unsigned char n);
unsigned char _cror_(unsigned char val, unsigned char n);
unsigned int  _irol_(unsigned int  val, unsigned char n);
unsigned int  _iror_(unsigned int  val, unsigned char n);
unsigned long _lrol_(unsigned long val, unsigned char n);
unsigned long _lror_(unsigned long val, unsigned char n);

功能

將 val 以位為單位循環左移/右移 n 位。高位移出後補入低位(左移)或低位移出補入高位(右移),無數據丟失。編譯器直接生成 RL A/RR A 指令序列,無函數調用開銷。

示例

#include <intrins.h>

void main() {
    unsigned int y = 0x00FF;
    y = _irol_(y, 4);  // y = 0x0FF0 (高4位 0000 移至低位)
    
    unsigned char c = 0x55; // 01010101b
    c = _crol_(c, 1);       // c = 0xAA (10101010b)
}

2. _nop_() —— 精確延時與流水線同步

原型

void _nop_(void);

功能

插入一條 NOP 指令(1 個機器週期,12T 模式下 1μs@12MHz)。編譯器內聯展開,不產生 CALL/RET 開銷。常用於:

  • 精確微秒級延時構建。
  • I/O 口讀寫間隔滿足建立/保持時間。
  • 流水線指令對齊、防止指令重排優化導致時序錯誤。

示例

P1_0 = 1;
_nop_(); _nop_();  // 2μs 延時,確保電平穩定
P1_0 = 0;

3. _testbit_() —— 原子位測試清零

原型

bit _testbit_(bit x);

功能

生成 JBC bit, rel 指令:若位 x 為 1,返回 1 並將該位硬件自動清零;若為 0,返回 0。整個操作不可中斷,屬原子操作。

限制

  • 參數必須是可位寻址的位變量(sbit、bit 類型、SFR 位)。
  • 不能用於複雜表達式中,必須單獨作為語句或賦值右值。

示例

sbit FLAG = P3^2;  // 假設 P3.2 為外部中斷標誌位

if (_testbit_(FLAG)) {
    // FLAG 原為 1,已被硬件自動清零,進入處理流程
    handle_interrupt();
}

進階應用技巧

1. 多位循環移位構建查表加密/校驗算法

unsigned char crc8_update(unsigned char crc, unsigned char data) {
    crc ^= data;
    for (int i = 0; i < 8; ++i) {
        if (crc & 0x80) crc = _crol_(crc, 1) ^ 0x07;
        else            crc = _crol_(crc, 1);
    }
    return crc;
}

2. 組合 _nop_ 實現精確延時函數

void delay_us(unsigned int us) {
    while (us--) {
        _nop_(); _nop_(); _nop_(); _nop_();  // 12MHz 下約 1μs,需根據晶振調整
        _nop_(); _nop_(); _nop_(); _nop_();
    }
}

3. 利用 _testbit_ 實現無鎖標誌位同步

主循環與中斷服務程序共享標誌位時,_testbit_ 保證「讀-清」原子性,避免競態條件。

注意事項與避坑指南

  1. 頭文件包含:必須 #include <intrins.h>,否則編譯器報錯「未定義標識符」。
  2. 參數類型匹配:_crol_ 接收 unsigned char,傳入 int 會隱式截斷高位,導致邏輯錯誤。
  3. 移位位數:n 超過類型位寬(如 char 移位 ≥8)行為未定義,需自行取模或判斷。
  4. 不可移植性:intrins.h 專屬 Keil C51,遷移到 SDCC、IAR、ARM 等平台需改寫為內聯匯編或平台庫函數。
  5. 優化影響:高優化等級下編譯器可能刪除看似無用的 _nop_(),需加 volatile 或降低優化等級。

總結

intrins.h 將 8051 強大的位操作指令集封裝為 C 函數,讓開發者在保持代碼可讀性的同時,榨乾單片機性能。熟練掌握循環移位、_nop_ 延時、_testbit_ 原子操作,是 C51 進階開發的必修課。但在現代 32 位 MCU(STM32 等)開發中,CMSIS、HAL 庫已提供更豐富、可移植的位操作 API,新項目建議優先使用標準庫。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved