Cách hiệu quả nhất để tạo một mảng bool trong C - AVR


7

Tôi đang sử dụng Atmega32 để đọc các cảm biến khác nhau bằng cách sử dụng ADC của nó.

Sử dụng logic kỹ thuật số và một vài bộ ghép kênh, tôi đã ghép toàn bộ PORTA, sử dụng PA0: 6 cho địa chỉ và PA7 làm đầu vào. Do đó, tôi có thể có tối đa 128 đầu vào chỉ từ một PORT.

Bây giờ, vì người dùng sẽ vận hành hệ thống thông qua máy tính (sử dụng RS232), nên có thể thêm hoặc xóa cảm biến, vì vậy hệ thống phải theo dõi địa chỉ nào miễn phí để thêm cảm biến và địa chỉ nào cần đọc.

Tôi đã nghĩ đến việc sử dụng một mảng boolean 128 bit làm cờ để cho biết nếu có một cảm biến tại một địa chỉ nhất định.

Mặc dù C không có hỗ trợ riêng cho các biến bit đơn, nhưng có thể sử dụng bitfield để đóng gói tối đa 8 "biến bool" vào một char không dấu.

Vì vậy, tôi đã tạo cấu trúc sau:

typedef struct bool_s{
      uint8_t bit1:1;
}bool_t;

Sau đó, tôi đã tạo ra một mảng loại bool_t với kích thước 128, hy vọng rằng mọi thứ sẽ được đóng gói độc đáo với nhau, nhưng sizeof()cho tôi biết rằng kích thước mảng là 128 byte thay vì 16 byte tôi mong đợi.

Về mặt kỹ thuật, tôi có thể tạo một cấu trúc đơn với 128 biến 1 bit:

typedef struct Flag_s{
      uint8_t F1:1;
      uint8_t F2:1;
      uint8_t F3:1;
      [...]
      uint8_t F128:1;
}Flag_t;

Vấn đề với cách tiếp cận này là trong khi nó làm giảm việc sử dụng bộ nhớ, nó không thực tế để sử dụng và nó chiếm quá nhiều bất động sản trong mã.

Có cách nào dễ dàng để tạo ra một số lượng lớn cờ hoặc tôi yêu cầu quá nhiều không? Ý tôi là, không giống như việc tiết kiệm 112 byte sẽ tạo ra sự khác biệt lớn khi bạn có sẵn 2K, nhưng nếu tôi cần nhiều cờ hơn thì sao?


Không nên điều này trên Stack Overflow ....
Joshpbarron 10/11/2015


1
@Joshpbarron Điều này đặc trưng cho C được nhúng, các biến boolean tồn tại trong C99 và bên cạnh đó, nó không giống như sử dụng thêm một vài byte ở đây và sẽ có bất kỳ sự khác biệt đáng kể nào khi bạn có sẵn GiBs của bộ nhớ và nếu tôi nói tôi đã sử dụng vi điều khiển, có lẽ họ sẽ bảo tôi đi đến trao đổi ngăn xếp EE.
Chi

Câu trả lời:


13

Các trường bit không hoạt động như thế. Câu trả lời của Cventu cho thấy một cách chính xác để sử dụng chúng, nhưng trong trường hợp này, tôi khuyên bạn nên tránh chúng hoàn toàn.

Thay vào đó, hãy tạo một mảng các giá trị 8 bit và sử dụng dịch chuyển và mặt nạ để truy cập nó:

uint8_t flags[16];

//Initialize the flags
void init_flags(void)
{
    for (i = 0; i < 16; i++)
    {
        flags[i] = 0x00;
    }
}

//Set one flag based on the address
void set_flag(uint8_t address)
{
    flags[address/8] |= 0x1 << (address % 8);
}

//Clear one flag based on the address
void clear_flag(uint8_t address)
{
    flags[address/8] &= ~(0x1 << (address % 8));
}

//Check whether a flag is set
bool get_flag_state(uint8_t address)
{
    return (flags[address/8] & (0x1 << (address % 0x8))) != 0x00;
}

Đây có lẽ là những gì trình biên dịch sẽ làm với truy cập trường bit và dù sao nó cũng dễ làm việc hơn. Một số trình tối ưu hóa rất tệ trong việc tối ưu hóa các trường bit, do đó trình biên dịch thậm chí có thể làm tồi tệ hơn. Tất cả các trình biên dịch tôi đã thấy phân chia lần lượt và mô đun bằng một công suất không đổi của hai thành các lệnh dịch chuyển phải và AND. Bạn có thể sử dụng các thao tác đó trực tiếp nếu bạn cảm thấy hoang tưởng:

flags[address>>3] |= 0x1 << (address & 0x7);

Các trường bit giống như các cấu trúc hơn là các mảng. Theo kinh nghiệm của tôi, chúng chỉ hữu ích cho những thứ có tên, như các trường đăng ký.


1
Trên các bộ xử lý tiên tiến hơn (như x86), bitfield thường được triển khai bằng các biến cơ bản lớn hơn, như uint32_t. Nhưng ý tưởng là như nhau: bitwise OR được sử dụng để đặt cờ, bitwise NOT + AND được sử dụng để xóa cờ và bitwise AND được sử dụng để kiểm tra các cờ, với mặt nạ được tạo bằng <<toán tử hoặc được định nghĩa là hằng số với các macro.
Laszlo Valko

2
Đó là một số số học đắt tiền (chia & mod) cho micros có công suất thấp.
John U

1
Mặc dù mã của bạn chung chung hơn, một số MCU (ví dụ PIC18) có khả năng đọc / đặt các bit đơn lẻ trong RAM trực tiếp. Điều này sẽ giảm tải rất nhiều. Người ta có thể kiểm tra điều này, vì trình biên dịch không phải lúc nào cũng nhận ra bạn đang làm gì ở đó.
sweber

2
@ John Tôi chưa bao giờ thấy phân chia hoặc phân chia mô đun bằng một sức mạnh không đổi của hai biên dịch thành bất cứ thứ gì khác ngoài lệnh shift và AND. Nhưng bạn chắc chắn không muốn chia hoặc sửa đổi theo một biến.
Adam Haun

4
Các lý do bitfields không làm việc như vậy là bởi vì mọi phần tử của một mảng phải có một địa chỉ và được tuân theo con trỏ số học, mà ngăn cản một phần tử từ chiếm nhỏ hơn kích thước của char (tức là một byte). Nhiều bitfield trong một cấu trúc có thể "chia sẻ" một byte, nhưng không có may mắn như vậy với các phần tử mảng.
hobbs 10/11/2015

9

Nghe có vẻ hơi khó hiểu, nhưng có lẽ một cái gì đó như thế này có thể giúp:

struct bits_field {
                       unsigned char bit_7 :1;
                       unsigned char bit_6 :1;
                       unsigned char bit_5 :1;
                       unsigned char bit_4 :1;
                       unsigned char bit_3 :1;
                       unsigned char bit_2 :1;
                       unsigned char bit_1 :1;
                       unsigned char bit_0 :1;

                   };

union dt {
             struct bits_field a;
             unsigned char b;
         };

Sau khi xác định chúng, hãy khai báo biến sau:

union dt my_data;

Bạn sẽ có thể viết toàn bộ nhóm togheter tám bit bằng cách sử dụng: my_data.b

Hoặc bạn có thể viết từng bit riêng lẻ bằng cách sử dụng: my_data.a.bit_7 (hoặc 6,5,4,3,2,1,0)

Trong trường hợp phù hợp với bạn, hãy sao chép 16 lần này (sử dụng một mảng hoặc struct) và bạn sẽ có thể xử lý 128 bit riêng lẻ.

Cho chúng tôi biết nếu nó làm việc! Chúc may mắn


Tôi cũng đã nghĩ đến việc sử dụng một cấu trúc với 8 biến 1 bit, nhưng sau đó tôi phải viết một số loại hàm để dịch số địa chỉ thành thứ gì đó tôi có thể sử dụng với một mảng như vậy, điều này sẽ làm tăng thêm sự nhầm lẫn và chi phí. Ồ, và nhân tiện, cuối cùng cũng có người chỉ cho tôi một ví dụ hay về cách loại dữ liệu hợp nhất có thể hữu ích! : P
Chi

Vấn đề chính ở đây là các trường bit có thể chứa bất kỳ số lượng bit và byte đệm nào, một trong nhiều điều khiến chúng không đáng tin cậy và không khả chuyển. Một liên minh không giải quyết điều đó.
Lundin

0

Tạo một cấu trúc trong đó bạn khai báo tám cờ bit cuối cùng là một byte. Sau đó tạo một mảng các cấu trúc 8 bit này.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.