2014-02-20 1 views
1

Я программирую PIC18F94K20 для совместной работы с кораблем MCC7941X I2C RTCC и 24AA128 I2C CMOS Serial EEPROM. В настоящее время у меня есть код, который успешно выполняет инициализацию секунд/дней/etc значений RTCC и запускает таймер, переключая светодиод на оборот каждой секунды.логические операторы и вычисление разрядности в C (программирование ПИК)

Я пытаюсь увеличить код, чтобы прочитать правильные данные для этих значений, однако я столкнулся с трудностями, когда пытаюсь объяснить различные «лишние» биты в значениях. Карта памяти может помочь прояснить мою проблему несколько:

RTCC Memory Map

Взятие, например, столбец часов, или адрес 02h. Бит 6 устанавливается как 1 для переключения 12-часового времени, добавляя 01000000 к бит времени. Я могу прочитать все содержимое байта по этому адресу, но я хочу использовать оператор if, чтобы определить, установлено ли 12 или 24 часа, и соответствующим образом скорректировать. Я не беспокоюсь о 10-часовых битах, так как я могу рассчитать это достаточно легко с циклом преобразования BCD (я думаю).

Ранее я использовал побитовый оператор OR в C, чтобы увеличить исходные данные часов до 24. Я инициализировал часы в этом конкретном случае 0x11 и установил 12-часовой бит управления, равный 0x64. При установке времени:

WriteI2C(0x11|0x64); 

который, как вы видите, использует побитовое ИЛИ.

При чтении часов, как я могу включить операторов в свой код, чтобы отделить лишние биты от фактических битов времени? Я попытался сделать что-то вроде этого:

current_seconds = ReadI2C(); 
current_seconds = ST & current_seconds; 

но это полностью разрушает все. Он компилируется, но устройство «застревает» в этой последовательности.

Как отделить бит ST/AMPM/VBATEN от фактических данных, которые мне нужны, и что бы хороший метод реализовать для циклов для различных условий, которые они представляют (например, чтение 12-часового времени, если бит 6 = 0 и 24 часа, если бит6 = 1 и т. Д.).

Я немного новичок C, и это мой первый набег на электронику, поэтому я очень ценю любую помощь. Благодарю.

+0

Я не думаю, что этот вопрос подходит здесь. просто прочитайте о побитовых операторах (|, &, <<) и бит-манипуляции. –

+0

Вы рекомендуете где угодно, что может быть более уместным? Извините, если я потерял его. – samanthapants

+0

Маскировка бит, который вы хотите посмотреть, выполняется с помощью оператора & и бит, установленного в 1, который вы хотите разделить. Итак, если вы смотрите на мои прочитанные секунды, возможно, просто конвертированы с помощью (((regdata & 0x7) * 10) + (regdata & 0xf), я думаю, – kenny

ответ

3

Чтобы удалить (ноль) немного, вы можете и значение с маской того, все остальные биты установлены, то есть, дополнение битов, которые вы хотите к нулю, например:

value_without_bit_6 = value & ~(1<<6); 

Изолировать бит внутри целого числа, вы можете И значение с маской, имеющей только эти биты. Для проверки флагов это все, что вам нужно сделать, например,

if (value & (1<<6)) { 
    // bit 6 is set 
} else { 
    // bit 6 is not set 
} 

Чтобы прочитать значение небольшого целого смещения в пределах большей один, первый изолировать биты, а затем переложить их прямо по индексу из самых низких бит (чтобы получить наименьший значащий бит в правильное положение), например:

value_in_bits_4_and_5 = (value & ((1<<4)|(1<<5))) >> 4; 

для более читаемый код, который вы должны использовать константы или #define d макросы для представления различных битовых масок, нужно, например,:

#define BIT_VBAT_EN (1<<3) 

if (value & BIT_VBAT_EN) { 
    // VBAT is enabled 
} 

Другой способ сделать это состоит в использовании битовых полей для определения организации битов, например:

typedef union { 
    struct { 
     unsigned ones:4; 
     unsigned tens:3; 
     unsigned st:1; 
    } seconds; 
    uint8_t byte; 
} seconds_register_t; 

seconds_register_t sr; 
sr.byte = READ_ADDRESS(0x00); 
unsigned int seconds = sr.seconds.ones + sr.seconds.tens * 10; 

Потенциальная проблема битовых полей является то, что код, генерируемый компилятором может быть непредсказуемо большой или неэффективны, что иногда вызывает озабоченность у микроконтроллеров, но, очевидно, лучше читать и писать. (Еще одна проблема, которая часто упоминается, заключается в том, что организация битовых полей, например, endianness, в значительной степени не определена стандартом C и, следовательно, не гарантируется переносимым для всех компиляторов и платформ. Однако я считаю, что низкоуровневая разработка для микроконтроллеров имеет тенденцию по сути, не переносимый, поэтому, если вы найдете правильную компоновку битов, я бы не рассматривал использование битовых полей «неправильно», особенно для проектов любителей.)

Однако вы можете выполнить аналогично читаемый синтаксис с макросами; это только сам макрос, который является менее читаемым:

#define GET_SECONDS(r) (((r) & 0x0F) + (((r) & 0x70) >> 4) * 10) 
uint8_t sr = READ_ADDRESS(0x00); 
unsigned int seconds = GET_SECONDS(sr); 
1

Относительно немного маскируются, вы будете хотеть, чтобы сделать модель этой карты памяти в вашем микроконтроллере. Самый простой, cudest способ сделать это состоит в #define число битовых масок, например:.

#define REG1_ST   0x80u 
#define REG1_10_SECONDS 0x70u 
#define REG1_SECONDS  0x0Fu 

#define REG2_10_MINUTES 0x70u 
... 

А потом при чтении каждого байта, маскировать данные, которые вы заинтересованы в Например:

bool st   = (data & REG1_ST) != 0; 
uint8_t ten_seconds = (data & REG1_10_SECONDS) >> 4; 
uint8_t seconds  = (data & REG1_SECONDS); 

Важной частью является минимизация количества «магических чисел» в исходном коде.

Запись данных:

reg1 = 0; 
reg1 |= st ? REG1_ST : 0; 
reg1 |= (ten_seconds << 4) & REG1_10_SECONDS; 
reg1 |= seconds & REG1_SECONDS; 

Пожалуйста, обратите внимание, что я ушел из I2C связь этого.

Смежные вопросы