loại 'bit' để lập trình vi điều khiển AVR


7

Tôi đã viết một mã cho vi điều khiển 8051, nơi tôi đã sử dụng loại bit, đại loại như thế này:

static bit done_flag = 0;    /* bit variable */

bit testfunc (               /* bit function */
  bit flag1,                 /* bit arguments */
  bit flag2)
{
.
.
.
return (0);                  /* bit return value */
}

Bây giờ tôi đang chuyển cái này sang bộ điều khiển AVR ATmega16. Tôi thấy rằng không có hỗ trợ cho
loại bit trong AVR.

Hướng dẫn sử dụng AVR-lib C cho biết:

Kiểu dữ liệu: char là 8 bit, int là 16 bit, dài là 32 bit, dài là 64 bit, float và double là 32 bit (đây là định dạng dấu phẩy động được hỗ trợ duy nhất), con trỏ là 16 bit (con trỏ hàm là địa chỉ từ, để cho phép đánh địa chỉ lên tới 128K dung lượng bộ nhớ chương trình). Có một tùy chọn -mint8 (xem Tùy chọn cho trình biên dịch C avr-gcc) để tạo int 8 bit, nhưng điều đó không được avr-libc hỗ trợ và vi phạm tiêu chuẩn C (int phải có ít nhất 16 bit). Nó có thể được gỡ bỏ trong một bản phát hành trong tương lai.

Vậy tôi nên làm gì bây giờ?


Bạn có thể sử dụng một boolkiểu dữ liệu nhưng tôi nghĩ rằng nó vẫn được lưu trữ dưới dạng một byte, nhưng không chắc chắn 100% về điều đó.
PeterJ

@PeterJ Không phải là trình biên dịch đóng gói bit Boolean?
Anindo Ghosh

@AnindoGhosh Đúng vậy, câu hỏi được gắn thẻ avr-gcc và tôi không nghĩ rằng gói đó, phiên bản cũ hơn nhưng tôi không chắc về các phiên bản mới nhất.
PeterJ

@PeterJ Đó không phải là một bài phê bình, chỉ là sự tò mò :-)
Anindo Ghosh

Câu trả lời:


4

Bạn có thể sử dụng một cấu trúc như thế này:

typedef struct {
    uint8_t bit0:1;
    uint8_t bit1:1;
    uint8_t bit2:1;
    uint8_t bit3:1;
    uint8_t bit4:1;
    uint8_t bit5:1;
    uint8_t bit6:1;
    uint8_t bit7:1;
} BitField;

typedef union {
    BitField asBits;
    uint8_t asByte;
} BitByte;

BitByte mBitField; 

Và để truy cập một bit cùng một lúc bạn chỉ phải

mBitField.asBits.bit3 = 1

3
Sử dụng cẩn thận. Một trình biên dịch mà tôi biết tạo ra mã rất kém hiệu quả cho thao tác bitfield (nhiều dịch chuyển trái & phải trong đó việc thực hiện mặt nạ & kiểm tra đơn giản sẽ được thực hiện).
MikeJ-UK

Trình biên dịch nào? Chỉ để biết.
Naeriel

Trình biên dịch Keil C51 - mặc dù nếu mã thời gian quan trọng được viết bằng trình biên dịch chương trình thì đó không phải là vấn đề.
MikeJ-UK

2
@Naeriel: Trình biên dịch nói chung sẽ có hiệu năng kém với bitfield trừ trường hợp phần cứng có thể trợ giúp và trình biên dịch biết về nó. Các nhà cung cấp trình biên dịch thường tập trung nỗ lực của họ vào việc tối ưu hóa các mẫu có khả năng được sử dụng bởi các lập trình viên đang tìm kiếm hiệu năng tốt. Những người tìm kiếm hiệu suất tốt trên 8x51 sẽ sử dụng bithoặc bdatakhông gian; vì bitfield không thể hoạt động tốt, người viết trình biên dịch có thể không nghĩ tối ưu hóa chúng là ưu tiên.
supercat

2
Lần trước tôi đã kiểm tra avr-gcc cũng không tốt trong việc tối ưu hóa các trường bit. Lời khuyên: Nếu bạn có đủ RAM cho nhiều boolgiây thay vì trường bit, hãy sử dụng bools. Nếu bạn muốn "đóng gói" các bit đó thay vào đó muốn có hiệu suất tốt nhất, hãy xem xét sử dụng các bit "handmade", ví dụ: thông qua #defines: #define MY_BIT_VALUE_1 _BV(0) #define MY_OTHER_BIT_VALUE _BV(1) ...được lưu trữ bên trong một uint8_tbiến duy nhất .
JimmyB

3

Như PeterJ đã đề cập trong bình luận của mình, tôi sẽ đề nghị sử dụng bool.

Bạn cần bao gồm thư viện stdbool.

#include <stdbool.h>

Như đã chỉ ra, trong AVRGCC, boollà 8 bit và chỉ là sự trừu tượng hóa của một uint8_t. Nếu bạn không thể sống với điều đó và cần lưu từng bit hoặc có hàng tấn cờ "có / không" toàn cầu (có thể chỉ ra thực tiễn mã hóa xấu), bạn có thể xem xét những gì Naeriel đã đăng trong câu trả lời của mình.

Tuy nhiên, sử dụng bool và đặt tên biến thích hợp (sử dụng "is" -prefix) sẽ tạo ra mã sạch hơn nhiều. Ví dụ sử dụng

bool IsOperationCompleted;

thay vì "xong_flag". Đó là cách rõ ràng hơn đối với người không biết mã chính xác những gì báo hiệu trạng thái.


0

Sử dụng char không dấu thay thế. Điều này sẽ sử dụng toàn bộ byte thay vì một chút mặc dù.


vì vậy thay vì bit tĩnh thực hiện_flag = 0;, nếu tôi thực hiện ký tự không dấu char xong_flag = 0; không nên có bất kỳ vấn đề gì (giả sử tôi có đủ bộ nhớ)?
gpuguy

Đúng. xin lưu ý rằng để so sánh có điều kiện 0 là sai và bất cứ điều gì không bằng 0 đều đúng. vì vậy, nếu (doing_flag) {do_mores_tuff ();} hoàn toàn hợp lệ
mouseuz

0

Bạn có thể sử dụng một cái gì đó như thế này:

#define bit_get(p,m) ((p)&(m)) #define bit_set(p,m) ((p)|=(m)) #define bit_clear(p,m) ((p)&=~(m)) #define BIT(x) (0x01<<(x))

Ví dụ sử dụng:

bit_set(DDRB,BIT(4))

đặt PB4 làm chân đầu ra.

Nguồn: http://www.avrfreaks.net/

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.