2013-04-15 28 views
5

Tôi có một 16 bit biến data, ví dụ:Bạn có thể lấy con trỏ tới byte dưới theo cách độc lập không?

volatile uint16_t data; 

tôi cần phải cư giá trị này dựa trên nội dung của hai thanh ghi 8 bit trên một bộ cảm biến bên ngoài. Chúng được truy cập qua I2C/TWI.

My TWI thói quen là async *, và có chữ ký:

bool twi_read_register(uint8_t sla, uint8_t reg, uint8_t *data, void (*callback)(void)); 

này đọc giá trị của reg trên sla vào *data, sau đó gọi callback().

Nếu tôi biết uint16_t được sắp xếp trong bộ nhớ như, nói, MSB LSB, sau đó tôi có thể làm:

twi_read_register(SLA, REG_MSB, (uint8_t *)&data, NULL); 
twi_read_register(SLA, REG_LSB, (uint8_t *)&data + 1, NULL); 

Tuy nhiên, tôi không thích nướng phụ thuộc endian vào mã của tôi. Có cách nào để đạt được điều này theo cách độc lập không?

(mặt lưu ý: Cách giải quyết thực tế của tôi vào lúc này liên quan đến việc sử dụng một cấu trúc, ví dụ:

typedef struct { 
    uint8_t msb; 
    uint8_t lsb; 
} SensorReading; 

nhưng tôi tò mò nếu tôi có thể làm điều đó với một đơn giản uint16_t)

EDIT

(* bởi async tôi có nghĩa là giai đoạn tách, tức là *data sẽ được đặt tại một số điểm trong tương lai, tại thời điểm đó, số điện thoại sẽ được thông báo qua chức năng callback nếu được yêu cầu)

+1

Tại sao bạn muốn để hạn chế bản thân để con trỏ truy cập vào các giá trị 16 bit? Hầu hết sẽ làm điều này với sự thay đổi và thêm hoặc vận hành. Tuy nhiên nếu bạn thực sự muốn làm điều đó với con trỏ, bạn có thể sử dụng các macro phát hiện và bù đắp cho endian-ness. –

+0

Không, bạn không thể ... đáng tin cậy. Sử dụng mặt nạ và thay đổi nếu bạn muốn mã đáng tin cậy và di động. –

+0

thực sự là mặt nạ và thay đổi không hoạt động, hoặc không? –

Trả lời

4

Những nội dung sau không hoạt động?

uint8_t v1, v2; 
twi_read_register(SLA, REG_MSB, &v1, NULL); 
twi_read_register(SLA, REG_LSB, &v2, NULL); 
data = ((uint16_t)v1<<8)|v2; 

Hoặc là data rất dễ bay hơi mà twi_read_register cần phải viết nó. Trong trường hợp đó tôi nghĩ rằng bạn đang mắc kẹt với mã phụ thuộc cuối cùng.

Như bạn đã chỉ ra bên dưới data thực sự là dễ bay hơi, bởi vì một thiết bị khác đang đọc nó. Vì vậy, một kết nối bộ nhớ ánh xạ được thiết lập giữa hai thiết bị có thể khác nhau về tính cuối cùng. Điều này có nghĩa là bạn đang mắc kẹt với mã phụ thuộc cuối cùng.

Bạn đề cập đến cấu trúc như một giải pháp thay thế, nhưng đó là một cách tiêu chuẩn để giải quyết vấn đề này.

#ifdef BIGENDIAN 
typedef struct 
{  uint8_t msb, lsb; 
} uint16_as_uint8_t; 
#else 
typedef struct 
{  uint8_t lsb, msb; 
} uint16_as_uint8_t; 
#endif 

Ngày đầu đó bạn có thể đặt một Note union

union 
{  uint16_as_uint8_t as8; 
     uint16_t   as16; 
}; 

rằng sau này là vi phạm các tiêu chuẩn C89 vì nó là ý định rõ ràng của bạn để viết một lĩnh vực của union và đọc từ một cái khác, dẫn đến giá trị không xác định. Từ off C99 này là (may mắn thay) được hỗ trợ. Trong C89 người ta sẽ sử dụng chuyển đổi con trỏ thông qua (char*) để làm điều này một cách di động.

Lưu ý rằng ở trên dường như ẩn tính xác thực theo cách di động, cấu trúc đóng gói cũng có thể khác với mục tiêu để nhắm mục tiêu và nó vẫn có thể phá vỡ một số mục tiêu.Đối với ví dụ trên, điều này là không thể, nhưng có một số mục tiêu kỳ quái xung quanh. Điều tôi đang cố gắng nói là có thể không thể lập trình di động ở cấp độ thiết bị này và tốt hơn là nên chấp nhận điều đó và cố gắng ẩn tất cả chi tiết trong giao diện mục tiêu nhỏ gọn, vì vậy hãy thay đổi một tệp tiêu đề cho mục tiêu sẽ đủ để hỗ trợ nó. Phần còn lại của mã sau đó có thể xem mục tiêu độc lập.

+1

Bạn không chắc chắn lý do tại sao bạn đang đề cập đến 'biến động '. –

+0

'twi_read_register' là không đồng bộ/chia pha, do đó,' v1' và 'v2' trong ví dụ của bạn sẽ không được đặt cho đến thời điểm không xác định trong tương lai. 'dữ liệu' sẽ có giá trị không xác định. – sapi

+0

Tôi hiểu. Sau đó, có thể bạn có thể thực hiện việc kết hợp thành 'uint16_t' khi bạn biết các giá trị đã sẵn sàng. –

0

Làm thế nào về một cái gì đó như thế này?

uint16_t myValue = ...; 
uint8_t LSB = (uint8_t)(myValue % 256); 
uint8_t MSB = (uint8_t)(myValue/256); 
+0

Đây là một cách tiếp cận phổ biến, mặc dù đọc của tôi về câu hỏi là nó đặt ra vấn đề theo một hướng khác, nhập một giá trị 16 bit từ hai bit 8 bit. –

+0

Tôi không thấy bất kỳ khó khăn nào với "myValue = MSB * 256 + LSB;" –

0
volatile uint16_t data; 
    uint16_t v = 1; 
    twi_read_register(SLA, REG_MSB, (uint8_t *)&data + *((uint8_t *)&v), NULL); 
    twi_read_register(SLA, REG_LSB, (uint8_t *)&data + *((uint8_t *)&v + 1), NULL); 
Các vấn đề liên quan