मेरे पास USART HAL के साथ एक एम्बेडेड प्रोजेक्ट है। यह USART एक बार में केवल 8 या 16 बिट संचारित या प्राप्त कर सकता है (मेरे द्वारा चुने गए usart रजिस्टर के आधार पर यानी सिंगल/डबल इन/आउट)। चूंकि यह 32-बिट एमसीयू है, मुझे लगा कि मैं लगभग 32-बिट फ़ील्ड को पास कर सकता हूं (जो मुझे समझने के लिए नेतृत्व किया गया है) यह एमपीयू के लिए बिट्स का अधिक कुशल उपयोग है। वही 64-बिट एमपीयू के लिए लागू होगा यानी लगभग 64-बिट पूर्णांकों को पास करेगा। शायद यह गुमराह करने वाली सलाह है, या संदर्भ से बाहर की गई सलाह है।

इसे ध्यान में रखते हुए, मैंने बिट-शिफ्टिंग के माध्यम से 8 बिट्स को 32-बिट फ़ील्ड में पैक किया है। मैं इसे usart पर tx और rx दोनों के लिए करता हूं।

केवल 8-बिट रजिस्टर के लिए कोड इस प्रकार है (16-बिट रजिस्टर में बिट-शिफ्टिंग के लिए केवल आधे राउंड हैं):

int zg_usartTxdataWrite(USART_data*         MPI_buffer,
                        USART_frameconf*    MPI_config,
                        USART_error*        MPI_error)
{

MPI_error = NULL;

if(MPI_config != NULL){
    zg_usartFrameConfWrite(MPI_config);
}

HPI_usart_data.txdata = MPI_buffer->txdata;

    for (int i = 0; i < USART_TXDATA_LOOP; i++){
        if((USART_STATUS_TXC & usart->STATUS) > 0){
            usart->TXDATAX = (i == 0 ? (HPI_usart_data.txdata & USART_TXDATA_DATABITS) : (HPI_usart_data.txdata >> SINGLE_BYTE_SHIFT) & USART_TXDATA_DATABITS);
        }
        usart->IFC |= USART_STATUS_TXC;
    }
    return 0;
}

संपादित करें: टिप्पणी अनुभाग में चर्चा की गई टर्नरी ऑपरेटर निहित पदोन्नति समस्या की स्पष्टता के लिए अतिरिक्त परिभाषाओं के साथ उपरोक्त कोड के तर्क को फिर से दर्ज करना

(HPI_usart और USART_data structs समान हैं, बस अलग-अलग स्तर हैं, मैंने तब से HPI_usart परत को हटा दिया है, लेकिन इस उदाहरण के लिए मैं इसे छोड़ दूंगा)

#define USART_TXDATA_LOOP 4
#define SINGLE_BYTE_SHIFT 8

typedef struct HPI_USART_DATA{

   ...
   uint32_t txdata;
   ...

}HPI_usart

HPI_usart HPI_usart_data = {'\0'};

const uint8_t USART_TXDATA_DATABITS = 0xFF;

int zg_usartTxdataWrite(USART_data*         MPI_buffer,
                        USART_frameconf*    MPI_config,
                        USART_error*        MPI_error)
{

MPI_error = NULL;

if(MPI_config != NULL){
    zg_usartFrameConfWrite(MPI_config);
}

HPI_usart_data.txdata = MPI_buffer->txdata;

    for (int i = 0; i < USART_TXDATA_LOOP; i++){
        if((USART_STATUS_TXC & usart->STATUS) > 0){
            usart->TXDATAX = (i == 0 ? (HPI_usart_data.txdata & USART_TXDATA_DATABITS) : (HPI_usart_data.txdata >> SINGLE_BYTE_SHIFT) & USART_TXDATA_DATABITS);
        }
        usart->IFC |= USART_STATUS_TXC;
    }
    return 0;
}

हालांकि, अब मुझे एहसास हुआ है कि यह संभावित रूप से हल होने की तुलना में अधिक समस्याएं पैदा कर रहा है क्योंकि मैं अनिवार्य रूप से इन बिट्स को आंतरिक रूप से एन्कोड कर रहा हूं, जिन्हें अलग-अलग डेटा परतों से/के माध्यम से पारित होने पर लगभग तुरंत डीकोड किया जाना चाहिए। मुझे लगता है कि यह एक चतुर और सेक्सी समाधान है, लेकिन अब मैं एक ऐसी समस्या को हल करने की कोशिश कर रहा हूं जिसे मुझे पहले स्थान पर नहीं बनाना चाहिए था। जैसे ऑफसेट होने पर वैरिएबल बिट फ़ील्ड कैसे निकालें यानी जीपीएस एनएमए वाक्यों में जहां पहले 8 बिट्स एक प्रासंगिक फ़ील्ड हो सकते हैं और बाकी 32 बिट फ़ील्ड हैं। तो यह इस तरह समाप्त होता है:

32-बिट सरणी सदस्य 0:

 bits 24-31      bits 15-23          bits 8-15            bits 0-7

| 8-बिट मान | 32-बिट मान ए, बिट्स 24-31 | 32-बिट मान ए, बिट्स 16-23 | 32-बिट मान ए, बिट्स 8-15 |

32-बिट सरणी सदस्य 1:

 bits 24-31             bits 15-23           bits 8-15               bits 0-7

| 32-बिट मान ए, बिट्स 0-7 | 32-बिट वैल्यू बी, बिट्स 24-31 | 32-बिट वैल्यू बी, बिट्स 16-23 | 32-बिट वैल्यू बी, बिट्स 8-15 |

32-बिट सरणी सदस्य 2:

 bits 24-31        15-23 8-15 ...

| 32-बिट मान बी, बिट्स 0-7 | आदि... | .... | .... |

उपरोक्त उदाहरण के लिए मैन्युअल डिकोडिंग की आवश्यकता है, जो मुझे लगता है कि ठीक है, लेकिन यह प्रत्येक एनएमए वाक्य के लिए अलग है और प्रोग्रामेटिक से अधिक मैनुअल लगता है।

मेरा प्रश्न यह है: बिटशिफ्टिंग बनाम सरणी अनुक्रमण, जो अधिक उपयुक्त है?

क्या मुझे 32-बिट सरणी सदस्य को प्रत्येक इनकमिंग/आउटगोइंग मान असाइन करना चाहिए और फिर उस तरह से इंडेक्स करना चाहिए? मुझे लगता है कि यह समाधान है क्योंकि यह न केवल अन्य परतों पर डेटा को पार करना आसान बना देगा, बल्कि मैं इस सभी बिट-शिफ्टिंग तर्क को खत्म करने में सक्षम होगा और फिर आरएक्स या टीएक्स फ़ंक्शन के बीच एकमात्र अंतर होगा डेटा जा रहा है दिशा।

इसका मतलब इंटरफ़ेस का एक छोटा सा पुनर्लेखन और परिणामी जीपीएस मॉड्यूल परत है, लेकिन यह कम काम की तरह लगता है और मेरी परियोजना में एक सस्ता सबक भी है।

इसके अलावा इस पर कोई विचार और सामान्य अनुभव बहुत अच्छा होगा।

1
BitShift 20 फरवरी 2019, 04:42

1 उत्तर

सबसे बढ़िया उत्तर

चूंकि यह 32-बिट MCU है, मुझे लगा कि मैं 32-बिट फ़ील्ड के आसपास भी जा सकता हूं

यह वास्तव में प्रोग्रामर की कॉल नहीं है। 8 या 16 बिट वेरिएबल को एक स्ट्रक्चर में रखें। यदि आवश्यक हो तो संकलक को पैडिंग जोड़ने दें। वैकल्पिक रूप से आप uint_fast8_t और uint_fast16_t का उपयोग कर सकते हैं।

मेरा प्रश्न यह है: बिटशिफ्टिंग बनाम सरणी अनुक्रमण, जो अधिक उपयुक्त है?

ऐरे इंडेक्सिंग सरणियों तक पहुँचने के लिए है। यदि आपके पास एक सरणी है, तो इसका इस्तेमाल करें। नहीं तो नहीं।

जबकि बाइट द्वारा डेटा बाइट के बड़े हिस्से को चबाना संभव है, ऐसे कोड को बहुत अधिक सावधानी से लिखा जाना चाहिए, ताकि विभिन्न सूक्ष्म प्रकार के रूपांतरण और पॉइंटर एलियासिंग बग में चलने से रोका जा सके।

सामान्य तौर पर, सीपीयू के शब्द आकार तक डेटा एक्सेस करते समय बिट शिफ्टिंग को प्राथमिकता दी जाती है, इस मामले में 32 बिट्स। यह तेज़ और पोर्टेबल भी है, ताकि आपको अंतहीनता को ध्यान में न रखना पड़े। यह पूर्णांकों के क्रमांकन/डी-क्रमांकन का पसंदीदा तरीका है।

2
Lundin 20 फरवरी 2019, 07:41