Как контролировать один бит внутри переменной?

Я работаю над контроллером LCD в мягком процессоре Microblaze, встроенном в FPGA. Чтобы подключиться к выходным файлам Verilog верхнего уровня, я использовал один 8-битный объект групповой политики.

В моем C я использовал переменные-заполнители для каждого бита, которым я управляю, например:

LcdDataBus = (cmd & 0xF0);  //Send higher nibble
LCD_RS = 0;
LCD_RW = 0;
LCD_EN = 1;

Если бы я программировал PIC, я мог бы просто определить каждый как вывод на UC, т.е. #define LCD_RS PORTA,0,

Тем не менее, я считаю, что я могу получить доступ к порту только через функцию

data = XIOModule_Initialize(&gpo, XPAR_IOMODULE_0_DEVICE_ID);
data = XIOModule_Start(&gpo);

куда data некоторая переменная.

Есть ли способ, которым я мог #define один бит в dataИтак, LCD_RS = бит0, LCD_RW = бит1, LCD_E = бит3, и моя шина данных LCD может быть следующими четырьмя битами?

2 ответа

Решение

Поскольку вам нужен очень точный определенный способ управления битами, самый безопасный способ - использовать чтение-изменение-запись.

volatile uint32_t *reg_address;
uint32_t data;
   data  = *reg_address;
   data |= (1<<LCD_RS_BIT_POS); // Set bit 
   // data &= ~(1<<LCD_RS_BIT_POS); // Clear bit 
   *reg_address = data;

Альтернативой является добавление бит-установленных / битовых адресных адресов к вашей карте регистра портов ЖК-дисплея (это код Verilog):

if (cpu_select && cpu_write)
  case (cpu_address[4:2])
  3'h0 : lcd_reg <= cpu_wdata[7:0]; // Direct write
  3'h1 : lcd_reg <= lcd_reg  |  cpu_wdata[7:0]; // set bit(s) write
  3'h2 : lcd_reg <= lcd_reg  & ~cpu_wdata[7:0]; // Clear bit(s) write
  ....
  endcase

Вы просили установить больше битов.
Основной подход - очистить все биты, которые вы хотите изменить, а затем снова установить их с нужными значениями.

Например: у вас есть 4-битное значение (биты 4,5,6,7), бит R/W (2) плюс бит адреса (0). Вы превращаете их в маску: 0b11110101.

   // Write to LCD
   data  = *reg_address;
   data &= ~0xF5; // Clear all the bits
   if (address==1)
     data |= (data_nibble<<4) | (1<<LCD_WRT_BIT_POS)  |(1<<LCD_ADR_BIT_POS) ; 
   else // Address 0 
     data |= (data_nibble<<4) | (1<<LCD_WRT_BIT_POS); 
   *reg_address = data;

Но....
В вашем случае вам, вероятно, нужно только отдельно контролировать сигнал "E". И вы знаете, что оно должно начинаться с низкого уровня. Вся процедура становится проще:

   uint32_t data;

   // Set the data, R/Wnot and RS all at the same time 
   if (write_data)
      data = nibble_data<<4; // R/Wn=0, RS=0. E=0
   else // Write command 
      data = nibble_data<<4 | (1<<RS_BIT_POS); // R/Wn=0, RS=1, E=0
   *reg_address = data;

   // Pulse E high and low:
   *reg_address = data | (1<<E_BIT_POS); // E high
   some_kind_of_wait_routine(); // Wait a while

   *reg_address = data; // E low 
   some_kind_of_wait_routine();  // Wait a while to guarantee minimum low time!

Для чтения вам не нужно устанавливать данные, но вы должны установить высокую строку чтения. Однако ЖК-дисплей может работать без чтения.

Вы можете создать битовые поля в структуре:

typedef struct {
  Uint32 LCD_RS : 1, /* 1 is the size in bit */
         LCD_RW : 1,
         LCD_E  : 1,
         bus    : 4
                : 15;
} data;
Другие вопросы по тегам