Share this

Porting and Optimization of Bit Operations in Embedded C Language

2026-04-06 05:06:18 · · #1
Introduction Microcontrollers are increasingly widely used and diverse. Due to the high readability and portability of embedded C language, which significantly reduces the workload of software engineers compared to assembly language, more and more microcontroller engineers are starting to use C programming. However, the portability of C language is limited to hardware-independent subroutines; hardware-specific subroutines are not portable. Bit operations (especially pin operations) are very common in microcontroller applications, such as reading and writing EEPROM and IC card data, and segmented LCD displays. Many integrated circuits with serial ports require the microcontroller to use software to implement I/O port read/write programs. How to make these subroutines both highly versatile and efficient in code generation is a problem that many software engineers are considering. This paper introduces two methods for porting C language bit operations. 1. Implementing Bitwise Operations Using Logical Operations Please see the following subroutine: INT8U Card102RdByte(void) { INT8U Temp8U, n = 8; do { Temp8U <<= 1; if ( PIN_CARD_SDA_RD() ) Temp8U |= 0x01; PIN_CARD_CLK_H(); PIN_CARD_CLK_L(); } while (-n); return Temp8U; } This is a subroutine that reads one byte from the 88SC102 card via a microcontroller pin. The program uses the μC/OSII syntax, i.e., variables and functions are written in "camelCase," while constants defined by `define` and inline functions are written in all uppercase with underscores. This program drives one pin to output the CARD_CLK high/low signal and reads CARD_SDA data bit by bit from another pin. 1.1 For MSP430 Series Microcontrollers This program is applied to the MSP430 microcontroller (this article uses the MSP430F413 microcontroller). The header file must contain the following definition: typedef unsigned char INT8U; #include #definePIN_CARD_SDA_RD()(P6IN & 0x01) #definePIN_CARD_CLK_H()P6OUT |=0x04 #definePIN_CARD_CLK_L()P6OUT &= ~0x04 The assembly result is as follows: In segment CODE, align 2, keepwithnext __code unsigned char Card102RdByte(void) Card102RdByte: 0000007E42MOV.B#0x8, R14 ??Card102RdByte_0: 0000024C5CRLA.BR12 000004D2B33400BIT.B#0x1, &0x34 0000080128JNC??Card102RdByte_1 00000A5CD3BIS.B#0x1, R12 ??Card102RdByte_1: 00000CE2D23500BIS.B#0x4, &0x35 000010E2C23500BIC.B#0x4, &0x35 0000147E53ADD.B#0xff, R14 0000164E93CMP.B#0x0, R14 000018F423 JNE??Card102RdByte_0 00001A3041RET This is almost identical to the result of manual assembly programming, demonstrating high code efficiency. 1.2 Application to 51 Series Microcontrollers To use this program with a 51 series microcontroller, the header file must include the following definitions: #include"Reg932.h" //Philips LPC932 microcontroller sbitCradClk=P0︿1; sbitCardSDA=P0︿0; #definePIN_CARD_SDA_RD()CardSDA #definePIN_CARD_CLK_H()CradClk=1 #definePIN_CARD_CLK_L()CradClk=0 The original program remains unchanged. The assembly result is as follows: ; FUNCTION Card102RdByte (BEGIN) ;—— Variable 'Temp8U' assigned to Register 'R7' —— ;—— Variable 'n' assigned to Register 'R6' —— 00007E08MOVR6,#08H 0002?C0007: 0002EFMOVA,R7 000325E0ADDA,ACC 0005FFMOVR7,A 0006308003JNBCardSDA,?C0008 0009430701ORLAR7,#01H 000C?C0008: 000CD281SETBCradClk 000EC281CLRCradClk 0010DEF0DJNZR6,?C0007 0012?C0009: 001222RET ; FUNCTION Card102RdByte (END) From the assembly result, it can be seen that the direct clearing and setting of bits has reached the simplest level, but the reading bit value is not ideal. 1.3 For 196/296 series microcontrollers: In microcontrollers such as the 80C196MC and 80C296SA, on-chip I/O ports can be window-mapped to low-end addresses. Using this method, I/O ports can be directly addressed, resulting in the shortest program code and the fastest execution speed. However, this makes C programs unportable. Without windowing, on-chip I/O ports are mapped to memory addresses and operate like ordinary memory addresses. Adding the following definitions to the header file allows you to utilize the original program: INT8UPOUT,PIN; #pragmalocate(POUT=0x880) #pragmalocate(PIN=0x881) //External I/O port address location #define PIN_CARD_SDA_RD() (PIN & 0x01) #define PIN_CARD_CLK_H() POUT |=0x04 #define PIN_CARD_CLK_L() POUT &= ~0x04 The assembled code is 56 bytes and has high efficiency. Using logical operations to implement bit operations makes the C program simple, clear, portable, and more readable. However, the 96 series microcontrollers cannot utilize JBC and JBS bit manipulation instructions, and the 51 series microcontrollers cannot utilize their unique bit manipulation instructions such as JB and JNB to improve code efficiency. Using bit field structures to implement bit operations can compensate for this deficiency. 2. Implementing Bit Operations Using Bit-Field Structures The original program is rewritten as follows: INT8U Card102RdByte(void) ① { ② INT8U n = 8; ③ #ifndef C51_ASM ④ bdata ACCImg; ⑤ #endif ⑥ do { ACC <<= 1; ⑦ GET_CARD_SDA(); ⑧ PIN_CARD_CLK_H(); PIN_CARD_CLK_L(); ⑨ }while(-n); ⑩ return ACC; } 2.1 Application in 51 Series Microcontrollers In C51, ACC does not need to be defined in every subroutine, so #define C51_ASM must be added at the beginning of the file. This way, lines ④, ⑤, and ⑥ will be ignored. Add the following definitions to the header file: `sbitACC_0=ACC︿0; #define GET_CARD_SDA() ACC_0 = CardSDA`. The remaining definitions are as described in Part I of this document. As a result, line ⑧ of the assembly code becomes two lines: "MOV C,CardSDA" and "MOV ACC_0,C". The function needs to return parameters through R7, and the program is now at its simplest state. ; FUNCTION Card102RdByte (BEGIN) ;—— Variable 'n' assigned to Register 'R7'—— 00007F08MOVR7,#08H 0002?C0007: 000225E0ADDA,ACC 0004A281MOVC,CardSDA 000692E0MOVACC_0,C 0008D280SETBCardClk 000AC280CLRCardClk 000CDFF4DJNZR7,?C0007 000EFFMOVR7,A 000F?C0008: 000F22RET ; FUNCTION Card102RdByte (END) A bit field structure can also be defined like in 196/296 using the JB instruction. Interested readers can try it themselves. 2.2 Application in 196/296 series microcontrollers To apply this program in 196/296, a local variable ACCImg needs to be defined, which is in lines ④, ⑤, and ⑥ of the previous program. Next, add the following bit-field structure definition to the header file: `typedef struct {unsigned Bit0:1; unsigned Bit1:1; unsigned Bit2:1; ​​unsigned Bit3:1; unsigned Bit4:1; unsigned Bit5:1; unsigned Bit6:1; unsigned Bit7:1; }Divide_to_bit; typedef union {INT8U Byte; Divide_to_bit DivBit; }bdata;` The port address variable should be defined as the following data type: `bdata PIN;` At the same time, add the following macro definitions to the header file: `#define ACC ACCImg.Byte #define ACC_0 ACCImg.DivBit.Bit0 #define GET_CARD_SDA() if (PIN.DivBit.Bit0) ACC |= 0x01;` This defines `ACCImg` as a low-end register, and `ACC` is its byte access form. The eighth line in the source code reads the pins. The assembly result uses JBC instructions, which reduces the number of bytes in the entire program compared to not using bit fields, thus achieving the goal of code optimization. cseg 0000Card102RdByte: ; Statement3 0000B10800Rldbn,#8 ; Statement7 0003 @ 0004 : 0003740101RaddbACCImg,ACCImg ; Statement8 0006B30181081CldbTmp0,PIN 000B 331C03jbcTmp0,3,@0005 000E 910101 RorbACCImg,#1 0011 @ 0005 : ; Statement9 0011 B30180081CldbTmp0,POUT 0016 91041CorbTmp0,#4 0019 C70180081CstbTmp0,POUT 001E 71FB1C andbTmp0,#0FBH 0021 C70180081C stbTmp0,POUT ; Statement10 00261500Rdecbn 0028980000RcmpbR0,n 002BD7D6bne @ 0004 ; Statement11 002DB0011C RldbTmp0,ACCImg 00302000 br @ 0001 ; Statement12 0032 @ 0001 : 0032F0ret 2.3 Application in MSP430 Series Microcontrollers The MSP430 series microcontrollers do not have bit manipulation instructions, so there is no need to define a bit field structure. You can directly define ACC as an unsigned 8-bit number. The header file is defined as follows: #ifndef C51_ASM // This line allows the header file to be shared with C51 typedef INT8U bdata; #define ACC ACCImg #define GET_CARD_SDA() if (P6IN & 0x01) ACC |= 0x01; #endif The assembly result is exactly the same as bit operations performed using logical operations. Conclusion There are three types of bit operations on pins: direct set or clear, inputting data from the port, and outputting data from the port. The first two have been introduced above. The C program for outputting data from the port is as follows: `do { OUT_SIO_DA(); CLK_H(); ACC <<= 1; // Shift expands clock pulse width CLK_L(); } while` Where: The first line `OUT_SIO_DA()` can be defined as a bit operation `SIO_SDA = ACC_7` in the C51 series; in the 196/296 and 430 series, it can be defined as an `if` statement as above. The bit operation program uses the name `ACC` as a local variable. In the C51, this is the main accumulator, which is very useful for programs of half-duplex devices such as the 2401 and IC cards, but it is not so convenient when SPI bus input/output is operated simultaneously. Implementing bit operations using logical operations does not present any portability obstacles. Bit operations in μC/OS-II are all implemented using logical operations. The bit field definition might have different allocation orders depending on the compiler, but considering that 32-bit high-speed CPUs wouldn't use software to simulate this kind of serial port operation, such programs would only be used in low-to-medium speed microcontrollers without on-chip cache, such as the 51, 196/296, and MSP430. Therefore, using bit fields to manipulate pins still makes sense. Whether to use logical operations or bit fields for bit manipulation is entirely a matter of personal preference. The compilers used in this article are Keil C51 V7.03, IAR C430 V2.10A, and Tasking C96 V5.0.
Read next

CATDOLL 136CM Tami (Customer Photos)

Height: 136cm Weight: 23.3kg Shoulder Width: 31cm Bust/Waist/Hip: 60/54/68cm Oral Depth: 3-5cm Vaginal Depth: 3-15cm An...

Articles 2026-02-22
CATDOLL Hanako Hard Silicone Head

CATDOLL Hanako Hard Silicone Head

Articles
2026-02-22
CATDOLL 146CM Vivian TPE

CATDOLL 146CM Vivian TPE

Articles
2026-02-22