2016-09-05 45 views
7

मैं एक औद्योगिक पीएलसी प्रोग्रामिंग कर रहा हूं और मुझे एक वीएफडी के साथ एक प्रोफेसर-बस संचार के लिए बिट्स में हेरफेर करना है। मुझे 2byte स्थिति मिलती है और 2byte कमांड भेजना पड़ता है। इस परिचालन के लिए मुझे वीएफडी ऑपरेटिंग प्राप्त करने के लिए बिट सेट करना होगा। उदाहरण के लिए:सी थोड़ा सेट (बिट मैनिपुलेशन)

    Byte n+1   Byte n 
PLC --> --------------------- --------------- --> VFD 
      15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 
      ---------+--------- | | | | -+- | | +- 0: Reglersperre/Freigabe 
        |   | | | | | | +--- 1: Freigabe/Schnellstopp 
        |   | | | | | +----- 2: Freigabe/Halt 
        |   | | | | +-------- 3..4: reserviert = 0 
        |   | | | +------------5: Parametersatz-Umschaltung 
        |   | | +------------- 6: Reset 
        |   | +--------------- 7: reserviert = 0 
        |   | 
        |   +----------------- 8: Lüften der Bremse ohne Antreibsfreigabe 
        +---------------------------- 9..15: reserviert = 0 

तो मुझे ऑपरेशन मोड में वीएफडी सेट करने के लिए बिट 0 सेट करना होगा। फिर मुझे ड्राइव शुरू करने के लिए बिट 2 सेट करने की आवश्यकता है।

अब मुझे question मिला जहां बिट-मैप्यूलेशन का वर्णन किया गया है और मुझे पता चला कि इस समाधान को काम करना चाहिए, लेकिन मैं वास्तव में इसे समझ नहीं पा रहा हूं।

क्या कोई यह बता सकता है कि यह क्यों काम करता है या काम नहीं करता है?

uint16_t change_bit(uint16_t command, unsigned int bit_nr, unsigned int val) { 
    /* command = 2byte command; bit_nr = bit to manipulate; 
    val = value bit should get (1;0) */ 
    command ^= (-val^command) & (1U << bit_nr); 
    return command; 
} 
+0

तुम सिर्फ सा 0 और बिट 2 1 पर सेट करने के लिए कोशिश कर रहे हैं:

यहाँ एक अधिक पठनीय शाखा संस्करण एक बदलाव के लिए एक बिटवाइज़ आपरेशन कारोबार है कि है? – dudeman

+0

-val सभी बिट्स को 1 के रूप में सेट करता है जब वैल == 1 और सभी बिट्स 0 के रूप में वैल == 0। –

+0

-val^कमांड कमांड करता है जब वह वैल 1 –

उत्तर

2

यह वास्तव में एक चालाक चाल है जो शाखाओं के बिना थोड़ा सा संशोधित करती है। यहां एक स्पष्टीकरण दिया गया है जो मानता है कि आप समझते हैं कि बिटवाई ऑपरेटर कैसे काम करते हैं।

की अभिव्यक्ति

(-val^command) & (1 << bit_nr) 

पहले उलटफेर कर शुरू करते हैं, चलो स्वैप -val और command

(command^-val) & (1 << bit_nr) 

फिर, अब वितरणात्मक कानून

(command & (1 << bit_nr))^(-val & (1 << bit_nr)) 

लागू होते हैं, पता है कि (यह मानते हुए दो पूरक) यदि val है 0, -val 0 (कोई सेट बिट्स) है, और अगर val 1 है, -val है -1 (सभी बिट्स सेट)

(command & (1 << bit_nr))^(val ? (1 << bit_nr) : 0) 

तो काम के रूप में लिखा जा सकता है एक अगर बयान

if (val) 
    command ^= (command & (1 << bit_nr))^(1 << bit_nr); 
else 
    command ^= command & (1 << bit_nr); 

यदि val 1 है, तो स्थिति bit_nr पर थोड़ा सा है जो इसके नकारात्मक मूल्य के साथ XORed है जो हमेशा बिट सेट करता है। यदि val 0 है, तो बिट स्वयं के साथ XORed है जो हमेशा बिट को साफ़ करता है। अन्य सभी बिट्स को 0 के साथ एक्सओआरड करते हैं जो उन्हें अपरिवर्तित छोड़ देता है।

uint16_t change_bit(uint16_t command, unsigned int bit_nr, unsigned int val) { 
    // Always clear the bit. 
    command &= ~(1u << bit_nr); 
    // Set the bit if val == 1. 
    command |= val << bit_nr; 
    return command; 
} 
4

ऐसा लगता है कि यह काम करता है, लेकिन यह बहुत ही आश्चर्यजनक और स्पष्ट नहीं है। कोई इसे "बहुत चालाक" कर सकता है। एक और अधिक स्पष्ट तरीका हो सकता है:

uint16_t change_bit(uint16_t command, unsigned int bit, bool value) 
{ 
    const uint16_t mask = 1u << bit; 
    if(value) 
    return command | mask; 
    else 
    return command & ~mask; 
} 

यह उस में एक कूद (if) है, लेकिन एक चतुर संकलक कि बाहर का अनुकूलन कर सकते हैं। यदि यह बहुत ही प्रदर्शन-महत्वपूर्ण कोड नहीं है, तो यह स्पष्टता के साथ अक्सर बेहतर होता है।

ध्यान दें कि बिट-स्तरीय हेरफेर करते समय बिना हस्ताक्षर किए गए प्रकारों का उपयोग करना एक अच्छा विचार है।

+0

जैसा कि मैं ' एक वास्तविक समय प्रणाली पर मी महत्वपूर्ण हो सकता है, लेकिन मेरे मामले में मैंने समय छोड़ दिया है। uint_16 मुखौटा में केवल 0s हैं और << ऑपरेशन के साथ आप वांछित स्थिति में 1 ले जाते हैं, है ना? अगर मैं सेट करना चाहता हूं 1 तक आप मुखौटा कर रहे हैं, जिसका मतलब है कि मुझे इस स्थिति में कोई फर्क नहीं पड़ता कि इससे पहले कि यह पहले क्या था। अगर मैं 0 पर सेट करना चाहता हूं तो आप उलटा मुखौटा जोड़ रहे हैं? नतीजा यह है कि सभी बिट्स को 1 जोड़ा जाता है केवल चयनित बिट को 0 जोड़ा जाता है, जिसका अर्थ है कि अन्य सभी बिट्स उनके पास मान रखते हैं और वांछित बिट 0 पर सेट होता है। मुझे यह सही लगता है? –

+0

@ जेराल्ड-जेहेटरर आप शाखा को हटाकर हटा सकते हैं: वापसी (कमांड और ~ मास्क) | मुखौटा; – mwk

+0

@GeraldZehetner हाँ, इसे छोड़कर "और"; "जोड़ें" नहीं। – unwind

संबंधित मुद्दे