2016-10-26 8 views
22

के दाएं घुमाएं मैं वर्तमान में सरल पूर्ण चरणों का उपयोग करके एक स्टेपर मोटर को नियंत्रित करने की कोशिश कर रहा हूं। इसका मतलब है कि मैं इस समय इस तरह के मूल्यों का एक अनुक्रम outputting हूँ:बिट-वार 4-बिट मान

1000 
0100 
0010 
0001 

मैं यह करने के लिए एक आसान तरीका सोचा था बस मेरी 4 बिट मूल्य लेने के लिए और प्रत्येक चरण के बाद, एक घुमाएं सही कार्रवाई करने के। "कोड" स्पष्ट रूप से वाक्य रचना के किसी भी प्रकार का पालन नहीं कर रहा है, यह बस वहाँ मेरे विचारों को वर्णन करने के लिए है:

step = 1000; 
//Looping 
Motor_Out(step) 
//Rotate my step variable right by 1 bit 
Rotate_Right(step, 1) 

मेरे समस्या यह है कि वहाँ स्पष्ट रूप से किसी भी 4 बिट सरल डेटा प्रकार है कि मैं इस के लिए उपयोग कर सकते हैं नहीं है , और यदि मैं 8-बिट हस्ताक्षरित int का उपयोग करता हूं तो मैं अंततः एमएसबी को 1 बंद कर दूंगा, जिसका अर्थ है कि मैं वास्तव में रुचि रखने वाला 4-बिट मान कुछ चरणों के लिए 0000 में बदल जाऊंगा।

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

+1

क्या आपके पास केवल 4 मान या कोई 4 बिट नंबर होगा? – Swanand

+0

अच्छी तरह से चरण-दर-चरण का उपयोग करके स्टेपर मोटर को नियंत्रित करना मतलब है कि मैं उपर्युक्त अनुक्रम को 4 पिनों पर उच्च/निम्न मानों के रूप में आउटपुट करता हूं जिसे मैंने सौंपा है। नीचे दिए गए उत्तरों को पढ़ने से मुझे इसे हल करने का मौका मिला है। मुझे पूरा यकीन नहीं है कि मैंने सिर्फ 'एक्स' चार मानों का एक सेट रखने के बारे में क्यों नहीं सोचा था जिसे मैं बस घुमाता हूं। – NT93

+0

http://stackoverflow.com/questions/15648116/bit-shifting-a-character-with-wrap-c –

उत्तर

10

इस के लिए गणित काफी सरल है कि वह हमेशा तालिका दृष्टिकोण की तुलना में तेजी हो जाएगा:

lea  eax, [0+rdi*8] 
shr  edi 
and  eax, 15 
or  eax, edi 
ret 
:

constexpr unsigned rotate_right_4bit (unsigned value) 
{ 
    return (value >> 1) | ((value << 3) & 15); 
} 

इस शाखा से मुक्त 86 विधानसभा के 5 लाइनों में बदल जाता है

या, वैकल्पिक रूप से, यदि आप वास्तव में इंडेक्स {3, 2, 1, 0} को इंडेक्स देखना चाहते हैं, तो आप उन्हें 2 फ़ंक्शंस में विभाजित कर सकते हैं, जो इंडेक्स को "increments" करता है, और दूसरा जो वास्तव में मान की गणना करता है :

constexpr unsigned decrement_mod4 (unsigned index) 
{ 
    return (index - 1) & 3; 
} 

constexpr unsigned project (unsigned index) 
{ 
    return 1u << index; 
} 
+0

यह एक अच्छा समाधान है, लेकिन एक तालिका का उपयोग सिर्फ दो mov निर्देश है। – 2501

+0

@ 2501 मुझे आपकी टेबल दृष्टिकोण भी पसंद है। और सिद्धांत रूप में आपका सुंदर कॉम्पैक्ट हो सकता है (अपने समाधान पर मेरी टिप्पणी देखें), लेकिन क्या आपने वास्तव में जेनरेट की गई असेंबली को देखा है? – KevinZ

+0

हां, बिना हस्ताक्षर किए गए प्रकार का उपयोग दो mov * s * – 2501

3

मैं आपके इच्छित मूल्यों के साथ एक सरणी बनाउंगा और सरणी से सही मान लोड करूंगा। यह आपको 4 बाइट ले जाएगा, यह तेज़ होगा, और यदि आप एक अलग मोटर प्रकार का उपयोग शुरू करते हैं तो भी अपनी समस्याओं का समाधान करें।

for example: 
const char values[4]={1,2,4,8}; 
int current_value = 0; 

.... 

if(++current_value>=4)current_value=0; 
motor = values[current_value]; 
+2

ध्यान दें कि यह वास्तविक मोटर मानों की तालिका में एक इंडेक्स के रूप में भ्रमित रूप से नामित 'current_value' चर का उपयोग करता है। – unwind

4

एक 8 बिट डेटा (जैसे uint8_t की तरह) प्रकार का प्रयोग करें। इसे शून्य में शुरू करें। उस बिट को सेट करें जिसे आप बाइट के निचले चार बिट्स में सेट करना चाहते हैं (उदा। value = 0x08)।

प्रत्येक "रोटेशन" के लिए एलएसबी (कम से कम महत्वपूर्ण बिट) लें और इसे सेव करें। एक कदम सही शिफ्ट करें। आपके द्वारा सहेजे गए बिट के साथ चौथे बिट को ओवरराइट करें।

कुछ इस तरह:

#include <stdio.h> 
#include <stdint.h> 

uint8_t rotate_one_right(uint8_t value) 
{ 
    unsigned saved_bit = value & 1; // Save the LSB 
    value >>= 1; // Shift right 
    value |= saved_bit << 3; // Make the saved bit the nibble MSB 
    return value; 
} 

int main(void) 
{ 
    uint8_t value = 0x08; // Set the high bit in the low nibble 
    printf("%02hhx\n", value); // Will print 08 
    value = rotate_one_right(value); 
    printf("%02hhx\n", value); // Will print 04 
    value = rotate_one_right(value); 
    printf("%02hhx\n", value); // Will print 02 
    value = rotate_one_right(value); 
    printf("%02hhx\n", value); // Will print 01 
    value = rotate_one_right(value); 
    printf("%02hhx\n", value); // Will print 08 again 

    return 0; 
} 

Live demonstration

21

केवल 4 संभावित मान के साथ आप 9 तत्वों के साथ एक मेज का प्रयोग करेंगे:

unsigned char current = 0x4; //value is: 0b0100 
unsigned char next = table_right[current]; //returns: 0b0010 
assert(next == 0x2); 

ऐसा करने से:

unsigned char table_right[] = { [0x1] = 0x8 , [0x2] = 0x1 , [0x4] = 0x2 , [0x8] = 0x4 }; 

आप अगले मूल्य की जरूरत है जब आप बस सूचकांक के रूप में वर्तमान मूल्य का उपयोग एक लूप में, सभी चार संभावित मूल्यों के माध्यम से लूप होगा।

सुविधाजनक रूप से, एक अवैध मान गुजरने से, शून्य वापस आ जाएगा, ताकि आप एक प्राप्त फ़ंक्शन लिख सकें जो अगली बार भी दावा करता है! = 0. आपको सरणी के मान को पार करने से पहले < 9 मान भी देना चाहिए।

+0

यह वास्तव में निफ्टी लगता है - मैं निश्चित रूप से कोशिश करूँगा, मुझे बस अपने सिर को लपेटना है कि कैसे काम करता है। – NT93

+0

अच्छी तरह से ध्यान दें कि सरणी के अन्य तत्व अभी भी प्रारंभ किए गए हैं (जो यह उत्तर नोट करता है), जीसीसी दस्तावेज़ देखें: https://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html – cat

+0

आप छुटकारा पा सकते हैं 'हस्ताक्षरित चार table_right [8] = {4, 8, 1, 0, 2, 0, 0, 0} करके अपरिभाषित व्यवहार का; '। फिर, अगला फ़ंक्शन 'table_right [current & 7]' वापस करें। यह टेबल को एक QWORD में फिट करता है। – KevinZ

7

आप 10001000b और आधुनिक 10000b

उपयोग कर सकते हैं और आप 01000100b00100010b00010001b10001000b दोहराने मिल सकती है।

उदाहरण के लिए

:

char x = 0x88; 
Motor_Out(x & 0xf); 
Rotate_Right(step, 1); 
+3

कृपया केवल कोड के साथ उत्तर पोस्ट न करें। इसके बजाय स्पष्टीकरण प्रदान करने का प्रयास करें। – user694733

8

IMO सबसे आसान तरीका है:

const unsigned char steps[ 4 ] = { 0x08, 0x04, 0x02, 0x01 }; 
int stepsIdx = 0; 
... 
const unsigned char step = steps[ stepsIdx++ ]; 
stepsIdx = stepsIdx % (sizeof(steps)/sizeof(steps[ 0 ])); 
+0

इसका निचला पक्ष यह है कि यदि यह एक लंबा चल रहा एप्लिकेशन है, तो चरण Idx ++ अंततः यूबी – UKMonkey

+5

@UKMonkey में परिणाम देगा: नहीं, यह नहीं होगा। उस अंतिम पंक्ति को देखें जो 'कदम Idx' को श्रेणी में क्लिप करता है? (व्यक्तिगत रूप से मैं इसे 'stepIdx &= 3;' के रूप में लिखूंगा लेकिन सबसे अधिक संभावना है कि एक अच्छा अनुकूलन संकलक आपके लिए ऐसा करेगा।) – usr2564301

+0

@ रैडलेक्सस: यदि अगली मोटर को 5 (या 7) चरणों की आवश्यकता होगी, तो एक अनुस्मारक ऑपरेशन होगा बेहतर विचार और आप सही हैं: संकलक को गति के बारे में सोचने दें)) – borisbn

15

बस एक int का उपयोग मूल्य धारण करने के लिए। बिट 4 के लिए कम से कम महत्वपूर्ण बिट कॉपी जब आप घुमाने और फिर 1 से सही यह पारी:

int rotate(int value) 
{ 
    value |= ((value & 1) << 4); // eg 1001 becomes 11001 
    value >>= 1;     // Now value is 1100 
    return value; 
} 
3

आप केवल उत्पादन 1, 2, 4 की जरूरत है, और 8. तो तुम चिह्नित करने के लिए एक काउंटर का उपयोग कर सकते जो उच्च सेट करने के लिए थोड़ा सा है।

Motor_Out(8 >> i); 
i = (i + 1) & 3; 

आप आधा चरणों में मोटर ड्राइव करने के लिए चाहते हैं, आप जो नंबर आप की जरूरत है स्टोर करने के लिए एक सरणी का उपयोग कर सकते हैं।

const unsigned char out[] = {0x8, 0xc, 0x4, 0x6, 0x2, 0x3, 0x1, 0x9}; 

Motor_out(out[i]); 
i = (i + 1) & 7; 

और आप इस तरह एक 4-बिट पूर्णांक घुमा सकते हैं।

((i * 0x11) >> 1) & 0xf 
+1

के बजाय मानक नहीं है कि '4 >> मैं निश्चित रूप से एक टाइपो है? – ilkkachu

+0

@ilkkachu हां। इस पर ध्यान दिलाने के लिए धन्यवाद। – v7d8dpo4

6

अगर मैं एक 8 बिट अहस्ताक्षरित int का उपयोग मैं अंत में बारी बारी से होगा 1 MSB के लिए रवाना

तो एक पारी का उपयोग करें और बिट reinitialize आप चाहते हैं जब मूल्य को जाता है शून्य। सी में घुमावदार ऑपरेशन नहीं है, इसलिए आपको कम से कम दो बदलाव करना होगा। (और मुझे लगता है कि सी ++ या तो घूमता नहीं है।)

x >>= 1; 
if (! x) x = 0x08; 

सरल, लिखने के लिए छोटा है, और यह क्या करता है में स्पष्ट। हां, यह एक शाखा में संकलित होगा (जब तक कि प्रोसेसर में सशर्त चालन ऑपरेशन न हो), लेकिन जब तक आपके पास यह बताने के लिए प्रोफाइलर आउटपुट न हो, तब तक आप इसके बारे में सोचने में अधिक समय खो देते हैं, उन प्रोसेसर चक्रों की तुलना में कभी भी।