RTC lib.cpp statement what meaning

Hi all, need help.
All day in google searching to understood the following C statement ( scrap from RTC libraries) :

@brief Disable alarm
@param alarm_num Alarm number to disable

void RTC_DS3231::disableAlarm(uint8_t alarm_num) {
uint8_t ctrl = read_i2c_register(DS3231_ADDRESS, DS3231_CONTROL);
----> ctrl &= ~(1 << (alarm_num - 1));<-----
write_i2c_register(DS3231_ADDRESS, DS3231_CONTROL, ctrl);

in particular I don't understand what make : ctrl &= ~(0x1 << (alarm_num - 1));
Maybe the whole statement needs to clear bit in ctrl register but I need to understand the single parts of statement for example what make (alarm_num - 1).
Many thanks to all

This is from the datasheet for the DS3231:

This is saying, based on the alarm number, which bit in the register to set to zero.
The tilda (~) is a bit inversion symbol. The (<<) is a left shift operation. The idea there is to create a bit mask which just set the desired bit to the desired value when "anded" with its original value.


For example, the bitmask to set A2IE in the control register to 0 when "anded" with the original value in the register (that is we touch only the desired bit and leave everything else as it is) looks like this: 0b11111101

To get there, we subtract 1 from the alarm number because the alarm numbers start from 1 and the register bit numbers start from zero. Then we left shift a '1' one bit to yield 0b00000010. Then we invert all the bits to yield 0b11111101. Thus we have the bit mask.

Hi 6v6gt,
one thing is not clear for me. Why the alarm numbers start from 1? .

Because most people who start by counting on fingers 1,2,3 have trouble with zero referenced computer counting 0,1,2.

The library writers were trying to accommodate the people who are more familiar with Alarm1 and Alarm2 than Alarm0 and Alarm1.

Good question. The data sheet appears to have given these alarms names like A1, A2 etc. but could have easily used names like A0, A1 etc.
I suppose it is something to do with the first alarm, the second alarm etc. Anyway, it is just a naming convention.

ok. Now is clear.

Another statement .I'm struggling with this

bool RTC_DS3231::setAlarm1(const DateTime &dt, Ds3231Alarm1Mode alarm_mode) {
uint8_t ctrl = read_i2c_register(DS3231_ADDRESS, DS3231_CONTROL);
if (!(ctrl & 0x04)) {
return false;

uint8_t A1M1 = (alarm_mode & 0x01) << 7; // Seconds bit 7.
uint8_t A1M2 = (alarm_mode & 0x02) << 6; // Minutes bit 7.
uint8_t A1M3 = (alarm_mode & 0x04) << 5; // Hour bit 7.
uint8_t A1M4 = (alarm_mode & 0x08) << 4; // Day/Date bit 7.
uint8_t DY_DT = (alarm_mode & 0x10)
<< 2; // Day/Date bit 6. Date when 0, day of week when 1.

What about (alarm_mode & 0x02) ? what does it mean? I know << means shift to left
thanks to all

Well, you can see what has happened. A real time clock needs to manage data like days, hours, minutes seconds etc. However, it uses byte registers (8 bits). But the numerical representation of say minutes, which has a value range of 0 to 59, requires only 7 bits. So there is one spare bit there. So a design decision has been made to tuck one of the alarm control bits in that spare bit instead of creating a new register. It is the same with most of the other time/date variables also. That is why there is this huge struggle to get at all the data relevant to the alarm settings.


bool RTC_DS3231::setAlarm1(const DateTime &dt, Ds3231Alarm1Mode alarm_mode) {
   uint8_t ctrl = read_i2c_register(DS3231_ADDRESS, DS3231_CONTROL);
   if (!(ctrl & 0x04)) {
      return false;
  . . .

is simply saying return the value of the bit labeled RS1 (bit 3) in the register named CONTROL.

It means, extract the value of bit 1 from the variable alarm_mode.
0x02 is equivalent to 0b0000010. Bits are numbered from right to left, starting at 0.
The & operator is a bitwise AND. 0 & 0 = 0; 0 & 1 = 0 ; 1 & 0 = 0 ; 1 & 1 = 1 ;

But, for an even better explanation, find a tutorial on bit manipulation.

quote="manu68, post:7, topic:890755"]
But, now if I see
uint8_t A1M4 = (alarm_mode & 0x08) << 4
following the same way , extract the value of bit 7 from the variable alarm_mode and then shift left four positions. So "Alarm_mode" value is 1 or 0,correct?

uint8_t DY_DT = (alarm_mode & 0x10) what bit extract?

uint8_t A1M4 = (alarm_mode & 0x08) << 4

alarm_mode & 0b00001000 // clear everything except bit 3 in alarm_mode.

A1M4 = alarm_mode & 0b00001000 << 4 // shift the whole thing 4 bits left so whatever was in bit 3 of alarm_mode is now in bit 7 of A1M4

uint8_t DY_DT = (alarm_mode & 0x10) what bit extract?

alarm_mode & 0x10 is equivalent to alarm_mode & 0b00010000 // extracts bit 4

Close. Anding with 4 (B00000100)picks up bit 2 which is INTCN and checks if the bit is set for an alarm interrupt. If not set, it returns false so you know the alarm is not set in the way the code intends.

Bit 2: Interrupt Control (INTCN). This bit controls the
INT/SQW signal. When the INTCN bit is set to logic 0,
a square wave is output on the INT/SQW pin. When the
INTCN bit is set to logic 1, then a match between the timekeeping registers and either of the alarm registers activates the INT/SQW output (if the alarm is also enabled).
The corresponding alarm flag is always set regardless of
the state of the INTCN bit. The INTCN bit is set to logic 1
when power is first applied.

ok. Thank you . Very precious support.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.