User Tools

Site Tools


amc2020:group_n:ds3231rtc

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
amc2020:group_n:ds3231rtc [2020/07/26 11:45] – [4.2 The Code Explained] jonas001amc2020:group_n:ds3231rtc [2021/08/24 17:35] (current) – external edit 127.0.0.1
Line 1: Line 1:
 +<html>
 +  <left>
 +    <a href="https://wiki.eolab.de/doku.php?id=amc2020:group_n:start"; onmouseover="style.color='green'";>
 +      <span style="color:#2E71B8"; onmouseover="style.color='green'"; onmouseout="style.color='#2E71B8'";>
 +        &#8617 Back to the main page
 +      </span>
 +    </a>
 +  </left>
 +</html>
 +
 ====== DS3231 Real Time Clock ====== ====== DS3231 Real Time Clock ======
  
Line 86: Line 96:
 There are a number of libraries available for the DS3231 RTC module, multiple of which were tested out. However, most of them are rather poorly documented, most have different features and some of them did not include the necessary function for the scope of the project. There are a number of libraries available for the DS3231 RTC module, multiple of which were tested out. However, most of them are rather poorly documented, most have different features and some of them did not include the necessary function for the scope of the project.
  
-In the end, after being inspired by the approach of {{https://github.com/RalphBacon/DS1307-DS3231-Real-Time-Clocks/blob/master/DS1307_DS3231_Reference_Code.ino|Ralph Bacon}}, I programmed the DS3231 only using the <html><span><font face="Courier New"><font style="color:#CD5307"><b>Wire</b></font>.h</font></span></html> library for I2C communication without a dedicated DS3231 library.+In the end, after being inspired by the approach of {{https://github.com/RalphBacon/DS1307-DS3231-Real-Time-Clocks/blob/master/DS1307_DS3231_Reference_Code.ino|Ralph Bacon}}, I programmed the DS3231 only using the <html><span><font face="Courier New"><font style="color:#CD5307"><b>Wire</font>.h</font></b></span></html> library for I2C communication without a dedicated DS3231 library.
  
 The sketch by Ralph Bacon only included setting and reading the time from the module and printing the result to the serial monitor. Most of this was used with only minor changes in this sketch. The implementation of the interrupt and the setting and clearing of alarm 1 was done by me. The sketch by Ralph Bacon only included setting and reading the time from the module and printing the result to the serial monitor. Most of this was used with only minor changes in this sketch. The implementation of the interrupt and the setting and clearing of alarm 1 was done by me.
 +
 +<WRAP center round info 100%>
 +For anyone interested, I also made my own library for the DS3231 RTC module. The library allows setting and reading the time as well as using alarm 1 and 2 and also allows to read and change the status and control registers. There are also functions included for directly printing the time and the register settings to the serial monitor for an easy setup.
 +
 +The library can be downloaded as a zip file from {{ :amc2020:group_n:ds3231lib.zip |here}}. 
 +
 +To understand what is done by the functions, I recommend checking the cpp file in the library folder and the [[https://datasheets.maximintegrated.com/en/ds/DS3231.pdf|DS3231 Datasheet]]. Example sketches will soon be included as well.
 +</WRAP>
 +
 ==== 4.1 The Code ==== ==== 4.1 The Code ====
  
Line 247: Line 266:
   Serial.print(Year);   Serial.print(Year);
   Serial.print("   Day of the week: ");   Serial.print("   Day of the week: ");
-  switch(Day){                                    //37+  switch(Day){                                    
     case 1:     case 1:
       Serial.println("Monday");       Serial.println("Monday");
Line 274: Line 293:
  
 ==== 4.2 The Code Explained ==== ==== 4.2 The Code Explained ====
- 
-<html> 
-<ol> 
-<li> 
-only the <b><font face=„Courier New“><font style="color:#CD5307">Wire</font>.h</font></b> library for I2C 
-</li> 
-</ol> 
-</html 
- 
- 
- 
  
 <html> <html>
Line 290: Line 298:
     <ol>     <ol>
         <li>         <li>
-            As explained before, no external library needs to be included, only the <b><font face=Courier New><font style="color:#CD5307">Wire</font>.h</font></b> library for I2C communication for reading and writing to the registers of the DS3231.+            As explained before, no external library needs to be included, only the <b><font face="Courier New"><font style="color:#CD5307">Wire</font>.h</font></b> library for I2C communication for reading and writing to the registers of the DS3231.
         </li>         </li>
         <li>         <li>
-            The I2C address of the DS3231 needs to be defined. By default (if no solder connections are used) it is hexadecimal <b><font face=Courier New>0x68</font></b>.+            The I2C address of the DS3231 needs to be defined. By default (if no solder connections are used) it is hexadecimal <b><font face="Courier New">0x68</font></b>.
         </li>         </li>
         <li>         <li>
Line 300: Line 308:
         <br>         <br>
         <li>         <li>
-            As explained in section 2, the alarm register mask bits define the alarm rate. For example, choosing the <b><font face=Courier New>ALARM_SECONDS_MINUTES_MATCH</font></b> option would trigger an alarm once every hour - when the seconds and the minutes in the alarm and the time register match.+            As explained in section 2, the alarm register mask bits define the alarm rate. For example, choosing the <b><font face="Courier New">ALARM_SECONDS_MINUTES_MATCH</font></b> option would trigger an alarm once every hour - when the seconds and the minutes in the alarm and the time register match.
         </li>         </li>
         <li>         <li>
-            The <b><font face=Courier New> <font style="color:#0098A3">byte</font></font></b> array <b><font face=Courier New>Alarm1MaskBits[6]</font></b> is basically an array containing table 2 with the mask bits for the alarm rates, where each array element represents a row from the table. The MSB in each element represents the bit for selecting either day or date format. Bit 6 is for A1M4, bit 5 is A1M3, and so on. The three LSBs are not needed and are just set to 0. Later on, using the previously defined (4) alarm 1 settings, one element is chosen from the array to set the alarm rate accordingly.+            The <b><font face="Courier New"> <font style="color:#0098A3">byte</font></font></b> array <b><font face="Courier New">Alarm1MaskBits[6]</font></b> is basically an array containing table 2 with the mask bits for the alarm rates, where each array element represents a row from the table. The MSB in each element represents the bit for selecting either day or date format. Bit 6 is for A1M4, bit 5 is A1M3, and so on. The three LSBs are not needed and are just set to 0. Later on, using the previously defined (4) alarm 1 settings, one element is chosen from the array to set the alarm rate accordingly.
         </li>         </li>
         <br>         <br>
         <li>         <li>
-            Here the Arduino pins for the interrupt (<b><font face=Courier New>IntPin</font></b>) and for the LED (<b><font face=Courier New>LEDPin</font></b>) are chosen. The interrupt pin has to be eitehr pin 2 or 3 for the UNO. the boolean variable <b><font face=Courier New>ledstatus</font></b> is just used in the main loop to switch the LED on and off.+            Here the Arduino pins for the interrupt (<b><font face="Courier New">IntPin</font></b>) and for the LED (<b><font face="Courier New">LEDPin</font></b>) are chosen. The interrupt pin has to be eitehr pin 2 or 3 for the UNO. the boolean variable <b><font face="Courier New">ledstatus</font></b> is just used in the main loop to switch the LED on and off.
         </li>         </li>
         <li>         <li>
-            When an interrupt is triggered, the MCU executes the attached interrupt service routine ISR which is defined later. The variable <b><font face=Courier New>Count</font></b> is used to count the number of interrupts triggered and is incremented by 1 in the ISR. Variables that are changed inside an ISR need to be configured as <b><font face=Courier New><font style="color:#0098A3">volatile</font></font></b>+            When an interrupt is triggered, the MCU executes the attached interrupt service routine ISR which is defined later. The variable <b><font face="Courier New">Count</font></b> is used to count the number of interrupts triggered and is incremented by 1 in the ISR. Variables that are changed inside an ISR need to be configured as <b><font face="Courier New"><font style="color:#0098A3">volatile</font></font></b>
             <br>             <br>
             Configuring a variable as volatile tells the Compiler to load the variable from the RAM instead of the a storage register. This is necessary when the variable can be changed from somewhere else than the code that it is appearing in, for example a concurrently executed function like an ISR.             Configuring a variable as volatile tells the Compiler to load the variable from the RAM instead of the a storage register. This is necessary when the variable can be changed from somewhere else than the code that it is appearing in, for example a concurrently executed function like an ISR.
Line 317: Line 325:
         <br>         <br>
         <li>         <li>
-            In the <b><font face=Courier New><font style="color:#5A6B0F">setup</font>()</font></b>, the method <b><font face=Courier New><font style="color:#CD5307">Wire</font><font style="color:#000000">.</font><font style="color:#CD5307">begin</font><font style="color:#000000">()</font></font></b> starts the I2C bus connecting DS3231 and Arduino UNO.+            In the <b><font face="Courier New"><font style="color:#5A6B0F">setup</font>()</font></b>, the method <b><font face="Courier New"><font style="color:#CD5307">Wire</font><font style="color:#000000">.</font><font style="color:#CD5307">begin</font><font style="color:#000000">()</font></font></b> starts the I2C bus connecting DS3231 and Arduino UNO.
         </li>         </li>
         <li>         <li>
-            The interrupt pin <b><font face=Courier New>IntPin</font></b> needs to be configured as an input. Furthermore, the DS3231's SQW pin (which is activated when an alarm is triggered) is an open drain output, which means it shorts the pin to GND when active. The Arduino interrupt pin (pin 2) needs to be HIGH normally, so that the voltage drop triggered by the SQW pin can be detected. As the Arduino has internal pullup resistors, activating them using <b><font face=Courier New><font style="color:#0098A3">INPUT_PULLUP</font></font></b> is sufficient for this.+            The interrupt pin <b><font face="Courier New">IntPin</font></b> needs to be configured as an input. Furthermore, the DS3231's SQW pin (which is activated when an alarm is triggered) is an open drain output, which means it shorts the pin to GND when active. The Arduino interrupt pin (pin 2) needs to be HIGH normally, so that the voltage drop triggered by the SQW pin can be detected. As the Arduino has internal pullup resistors, activating them using <b><font face="Courier New"><font style="color:#0098A3">INPUT_PULLUP</font></font></b> is sufficient for this.
         </li>         </li>
         <li>         <li>
-            The pin for the LED needs to be configured as an <b><font face=Courier New><font style="color:#0098A3">OUTPUT</font></font></b> to switch the LED on and off.+            The pin for the LED needs to be configured as an <b><font face="Courier New"><font style="color:#0098A3">OUTPUT</font></font></b> to switch the LED on and off.
         </li>         </li>
         <li>         <li>
-            Here the later defined function <b><font face=Courier New>setRTCTime</font></b> is called to configure the time, date and day of the week of the DS3231. As an argument it needs the seconds, minutes, hours, day of the week, day of the month, month and year. After the time is configured for the first time, this should be commented out to prevent the time from being reset every time the Arduino restarts.+            Here the later defined function <b><font face="Courier New">setRTCTime</font></b> is called to configure the time, date and day of the week of the DS3231. As an argument it needs the seconds, minutes, hours, day of the week, day of the month, month and year. After the time is configured for the first time, this should be commented out to prevent the time from being reset every time the Arduino restarts.
         </li>         </li>
         <li>         <li>
-            The function <b><font face=Courier New>setRTCAlarm1</font></b> configures the seconds, minutes, hours, date or day of the week, as well as the setting for the alarm rate for alarm 1 by writing to the alarm registers. Furthermore it activates alarm 1 and enables interrupts in the status register. The function is defined later on. If the alarm is already configured and working, this line of code can be commented out as well.+            The function <b><font face="Courier New">setRTCAlarm1</font></b> configures the seconds, minutes, hours, date or day of the week, as well as the setting for the alarm rate for alarm 1 by writing to the alarm registers. Furthermore it activates alarm 1 and enables interrupts in the status register. The function is defined later on. If the alarm is already configured and working, this line of code can be commented out as well.
         </li>         </li>
         <li>         <li>
-            To attach an interrupt on the Arduino UNO, the function <b><font face=Courier New><font style="color:#CD5307">attachInterrupt</font>()</font></b> is used. As first argument the function <b><font face=Courier New><font style="color:#CD5307">digitalPinToInterrupt</font>()</font></b> is given and as its argument the Arduino interrupt pin (2) is submitted. Afterwards, the function expects the name of the interrupt service routine which is called whenever an interrupt is triggered; in this sketch it is caleld ISRLED. The last argument is the interrupt mode. There are 5 (for the UNO 4) different modes. Here the mode <b><font face=Courier New><font style="color:#0098A3">FALLING</font></font></b> is necessary which indicates that the interrupt is triggered whenever the interrupt pin goes from HIGH to LOW.+            To attach an interrupt on the Arduino UNO, the function <b><font face="Courier New"><font style="color:#CD5307">attachInterrupt</font>()</font></b> is used. As first argument the function <b><font face="Courier New"><font style="color:#CD5307">digitalPinToInterrupt</font>()</font></b> is given and as its argument the Arduino interrupt pin (2) is submitted. Afterwards, the function expects the name of the interrupt service routine which is called whenever an interrupt is triggered; in this sketch it is called ISRLED. The last argument is the interrupt mode. There are 5 (for the UNO 4) different modes. Here the mode <b><font face="Courier New"><font style="color:#0098A3">FALLING</font></font></b> is necessary which indicates that the interrupt is triggered whenever the interrupt pin goes from HIGH to LOW.
         </li>         </li>
         <br>         <br>
         <li>         <li>
-            The main <b><font face=Courier New><font style="color:#5A6B0F">loop</font>()</font></b> loop itself is very short. Firstly, by removing the alarm 1 flag in the DS3231 status register with the function <b><font face=Courier New>clearAlarm1()</font></b> defined below, alarm 1 is reset. In the final application this will only be done once after the MCU wakes up from deep sleep.+            The main <b><font face="Courier New"><font style="color:#5A6B0F">loop</font>()</font></b> loop itself is very short. Firstly, by removing the alarm 1 flag in the DS3231 status register with the function <b><font face="Courier New">clearAlarm1()</font></b> defined below, alarm 1 is reset. In the final application this will only be done once after the MCU wakes up from deep sleep.
         </li>         </li>
         <li>         <li>
-            The <b><font face=Courier New><font style="color:#5A6B0F">if</font></font></b> control structure checks the variable <b><font face=Courier New>Count</font></b>. In this example, the alarm was chosen to go off every second (12), so the <b><font face=Courier New>Count</font></b> variable is incremented by 1 once a second, so the condition becomes true after 1 second. It then resets the counter variable and changes the status of the LED. So in conclusion, it switches the LED on and off in 1 second intervals. The intervals can be changed by adjusting the condition. This is just used as an indicator to check if the interrupt is working as supposed to.+            The <b><font face="Courier New"><font style="color:#5A6B0F">if</font></font></b> control structure checks the variable <b><font face="Courier New">Count</font></b>. In this example, the alarm was chosen to go off every second (12), so the <b><font face="Courier New">Count</font></b> variable is incremented by 1 once a second, so the condition becomes true after 1 second. It then resets the counter variable and changes the status of the LED. So in conclusion, it switches the LED on and off in 1 second intervals. The intervals can be changed by adjusting the condition. This is just used as an indicator to check if the interrupt is working as supposed to.
         </li>         </li>
         <br>         <br>
         <li>         <li>
-            The function <b><font face=Courier New>decToBCD()</font></b> returns and expects as an arguement a  <b><font face=Courier New><font style="color:#0098A3">byte</font></font></b> type value. It is used to convert a decimal number DEC to a binary coded decimal number BCD. As explained before, the time and alarm registers of the DS3231 are written in BCD format. However, DEC format is much more intuitive for the user to set the alarm and time of the module. Therefore, this function is used to convert the decimals given as function arguments for the two functions called in the setup (11 & 12) to the format that the DS3231 understands.+            The function <b><font face="Courier New">decToBCD()</font></b> returns and expects as an arguement a  <b><font face="Courier New"><font style="color:#0098A3">byte</font></font></b> type value. It is used to convert a decimal number DEC to a binary coded decimal number BCD. As explained before, the time and alarm registers of the DS3231 are written in BCD format. However, DEC format is much more intuitive for the user to set the alarm and time of the module. Therefore, this function is used to convert the decimals given as function arguments for the two functions called in the setup (11 & 12) to the format that the DS3231 understands.
         </li>         </li>
         <li>         <li>
Line 350: Line 358:
         <br>         <br>
         <li>         <li>
-            The function <b><font face=Courier New>ISRLED()</font></b> is serving as the interrupt service routine called when an interrupt is triggered. Here it is used only to increment the counter variable and active the flag for the interrupt status. There are a few things to consider when writing an interrupt service routine. ISRs should always be as as short as possible because when they are called, the normal program stops as long as they are running; so functions that need a lot of time like print functions should be avoided. Furthermore, <b><font face=Courier New><font style="color:#CD5307">delay</font>()</font></b>, <b><font face=Courier New><font style="color:#CD5307">millis()</font>()</font></b> or <b><font face=Courier New><font style="color:#CD5307">micros</font>()</font></b> are not working inside an ISR and variables used in an ISR need to be <b><font face=Courier New><font style="color:#0098A3">volatile</font></font></b>. More information can be found on the <a href="https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/">Arduino Reference page</a>.+            The function <b><font face="Courier New">ISRLED()</font></b> is serving as the interrupt service routine called when an interrupt is triggered. Here it is used only to increment the counter variable and active the flag for the interrupt status. There are a few things to consider when writing an interrupt service routine. ISRs should always be as as short as possible because when they are called, the normal program stops as long as they are running; so functions that need a lot of time like print functions should be avoided. Furthermore,<b><font face="Courier New"><font style="color:#CD5307">delay</font>()</font></b>, <b><font face="Courier New"><font style="color:#CD5307">millis()</font>()</font></b> or <b><font face="Courier New"><font style="color:#CD5307">micros</font>()</font></b> are not working inside an ISR and variables used in an ISR need to be <b><font face="Courier New"><font style="color:#0098A3">volatile</font></font></b>. More information can be found on the <a href="https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/">Arduino Reference page</a>.
         </li>         </li>
         <br>         <br>
         <li>         <li>
-            As explained before (11), <b><font face=Courier New>setRTCTime()</font></b> is used to configure the time registers of the DS3231.+            As explained before (11), <b><font face="Courier New">setRTCTime()</font></b> is used to configure the time registers of the DS3231.
         </li>         </li>
         <li>         <li>
-            The method <b><font face=Courier New><font style="color:#CD5307">Wire</font>.<font style="color:#CD5307">beginTransmission</font>()</font></b> starts a transmission on the I2C bus in the slave receiver mode. As a function argument, the already defined I2C address (2) is given. Only the slave with that exact address will respond to the now following communication.+            The method <b><font face="Courier New"><font style="color:#CD5307">Wire</font>.<font style="color:#CD5307">beginTransmission</font>()</font></b> starts a transmission on the I2C bus in the slave receiver mode. As a function argument, the already defined I2C address (2) is given. Only the slave with that exact address will respond to the now following communication.
         </li>         </li>
         <li>         <li>
-            The method <b><font face=Courier New><font style="color:#CD5307">Wire</font>.<font style="color:#CD5307">write</font>()</font></b> transmits the byte given as an argument. The first <b><font face=Courier New><font style="color:#CD5307">write</font>()</font></b> sets the register pointer of the DS3231. Here the pointer is set to <b><font face=Courier New>0x00</font></b>, which means that the following input is stored in the register with the address <b><font face=Courier New>0x00</font></b> which is the time register for the seconds.+            The method <b><font face="Courier New"><font style="color:#CD5307">Wire</font>.<font style="color:#CD5307">write</font>()</font></b> transmits the byte given as an argument. The first <b><font face="Courier New"><font style="color:#CD5307">write</font>()</font></b> sets the register pointer of the DS3231. Here the pointer is set to <b><font face="Courier New">0x00</font></b>, which means that the following input is stored in the register with the address <b><font face="Courier New">0x00</font></b> which is the time register for the seconds.
         </li>         </li>
         <li>         <li>
-            Now the value for <b><font face=Courier New>Second</font></b> given as function argument is converted into BCD format and is then sent on the I2C bus to the DS3231 which overwrites the <b><font face=Courier New>0x00</font></b> register with the new information. That means the seconds of the DS3231 are configured. The register pointer then automatically jumps to the next register which is storing the minutes. As all the time registers are grouped together, all of them can be configured in one transmission, one after the other.+            Now the value for <b><font face="Courier New">Second</font></b> given as function argument is converted into BCD format and is then sent on the I2C bus to the DS3231 which overwrites the <b><font face="Courier New">0x00</font></b> register with the new information. That means the seconds of the DS3231 are configured. The register pointer then automatically jumps to the next register which is storing the minutes. As all the time registers are grouped together, all of them can be configured in one transmission, one after the other.
         </li>         </li>
         <li>         <li>
-            When all the registers are configured and the DS3231 has a new time set, the I2C transmission is stopped with <b><font face=Courier New><font style="color:#CD5307">Wire</font>.<font style="color:#CD5307">endTransmission</font>()</font></b>.+            When all the registers are configured and the DS3231 has a new time set, the I2C transmission is stopped with <b><font face="Courier New"><font style="color:#CD5307">Wire</font>.<font style="color:#CD5307">endTransmission</font>()</font></b>.
         </li>         </li>
         <br>         <br>
         <li>         <li>
-            Here follows the definition of function <b><font face=Courier New>setRTCAlarm1()</font></b> which was used in the <b><font face=Courier New><font style="color:#5A6B0F">setup</font>()</font></b> (12).+            Here follows the definition of function <b><font face="Courier New">setRTCAlarm1()</font></b> which was used in the <b><font face="Courier New"><font style="color:#5A6B0F">setup</font>()</font></b> (12).
         </li>         </li>
         <li>         <li>
             To configure the four registers of alarm 1, it is necessary to convert the seconds, minutes, hours and date/day into BCD format again. However, as can be seen in table 1, the alarm registers also contain the mask bits for the alarm rate which are stored as A1M1 to A1M4 in the MSBs of the four. The Which mask bit is used for which register is determined by the element chosen in the mask bit array (5).             To configure the four registers of alarm 1, it is necessary to convert the seconds, minutes, hours and date/day into BCD format again. However, as can be seen in table 1, the alarm registers also contain the mask bits for the alarm rate which are stored as A1M1 to A1M4 in the MSBs of the four. The Which mask bit is used for which register is determined by the element chosen in the mask bit array (5).
             <br>             <br>
-            The function <b><font face=Courier New><font style="color:#CD5307">bitRead</font>()</font></b> is used to read a single bit from a byte. The first argument is the byte to read from; here the <b><font face=Courier New>Alarm1MaskBits[]</font></b> array is used and the byte element to read is determined by the <b><font face=Courier New>Setting</font></b> (4). <b><font face=Courier New>ALARM_ONCE_PER_SECOND</font></b> thus means the first element from the array which is <b><font face=Courier New>B01111000</font></b>, is chosen to read from. The second argument is the number of the bit, where 0 is the LSB and 7 is the MSB. The bit mask for the seconds register is the 4th bit from the right, so bit number 3. To now place that bit correctly in the <b><font face=Courier New>Second</font></b> byte, it mus be written inthe A1M1 bit (MSB). The MSB has a decimal value of 128, so the mask bit is just multiplied by 128 which puts it to the front.+            The function <b><font face="Courier New"><font style="color:#CD5307">bitRead</font>()</font></b> is used to read a single bit from a byte. The first argument is the byte to read from; here the <b><font face="Courier New">Alarm1MaskBits[]</font></b> array is used and the byte element to read is determined by the <b><font face="Courier New">Setting</font></b> (4). <b><font face="Courier New">ALARM_ONCE_PER_SECOND</font></b> thus means the first element from the array which is <b><font face="Courier New">B01111000</font></b>, is chosen to read from. The second argument is the number of the bit, where 0 is the LSB and 7 is the MSB. The bit mask for the seconds register is the 4th bit from the right, so bit number 3. To now place that bit correctly in the <b><font face="Courier New">Second</font></b> byte, it mus be written inthe A1M1 bit (MSB). The MSB has a decimal value of 128, so the mask bit is just multiplied by 128 which puts it to the front.
             <br>             <br>
             This same process is repeated for the minutes hours and days. What changes is the position of the respective mask bit in the mask bit array element; for minutes it is 4, for hours 5 and for days or date 6.             This same process is repeated for the minutes hours and days. What changes is the position of the respective mask bit in the mask bit array element; for minutes it is 4, for hours 5 and for days or date 6.
             <br>             <br>
-            The hour format will automatically be 24 hours like in the time register because bit 6 stays always 0 (see table 1). However, when the alarm rate is chosen to be either once a week or once a month, i.e. days/date are matched, that has to be changed in the code. Therefore, the MSB of the array element contains a 0 for matching the date and a 1 for matching the day (table 2). This value is read from the array with another <b><font face=Courier New><font style="color:#CD5307">bitRead</font>()</font></b> and the retrieved value is multiplied with 64 to put it to bit 6 of the <b><font face=Courier New>DayDate</font></b> byte.+            The hour format will automatically be 24 hours like in the time register because bit 6 stays always 0 (see table 1). However, when the alarm rate is chosen to be either once a week or once a month, i.e. days/date are matched, that has to be changed in the code. Therefore, the MSB of the array element contains a 0 for matching the date and a 1 for matching the day (table 2). This value is read from the array with another <b><font face="Courier New"><font style="color:#CD5307">bitRead</font>()</font></b> and the retrieved value is multiplied with 64 to put it to bit 6 of the <b><font face="Courier New">DayDate</font></b> byte.
         </li>         </li>
         <li>         <li>
-            After configuring the values of the bytes for setting the alarm, another transmission to the RTC is started and the register pointer is set to register <b><font face=Courier New>0x07</font></b> containing the alarm settings for the seconds. Then the before calculated bytes are transmitted one after another to configure the alarm. and the transmission is ended.+            After configuring the values of the bytes for setting the alarm, another transmission to the RTC is started and the register pointer is set to register <b><font face="Courier New">0x07</font></b> containing the alarm settings for the seconds. Then the before calculated bytes are transmitted one after another to configure the alarm. and the transmission is ended.
         </li>         </li>
         <li>         <li>
-            To activate alarm 1 and enable the interrupt output throug the SQW pin, another transmission is started and the register pointer is set to <b><font face=Courier New>0x0E</font></b> which is the DS3231's control register.+            To activate alarm 1 and enable the interrupt output throug the SQW pin, another transmission is started and the register pointer is set to <b><font face="Courier New">0x0E</font></b> which is the DS3231's control register.
         </li>         </li>
         <li>         <li>
-            Then the byte <b><font face=Courier New>B00011101</font></b> is transmitted through I2C to configure the control register. What it does can be found in detail in the datasheet on page 13. In short, what each bit does is:+            Then the byte <b><font face="Courier New">B00011101</font></b> is transmitted through I2C to configure the control register. What it does can be found in detail in the datasheet on page 13. In short, what each bit does is:
             B: 0 - turn on the oscillator; 0 - no square wave output; 0 - no temperature conversion command; 1 - square wave frequency setting - 1 square wave frequency setting; 1 -activate interrupt output; 0 - deactivate alarm 2; 1 - activate alarm 1.             B: 0 - turn on the oscillator; 0 - no square wave output; 0 - no temperature conversion command; 1 - square wave frequency setting - 1 square wave frequency setting; 1 -activate interrupt output; 0 - deactivate alarm 2; 1 - activate alarm 1.
             <br>             <br>
Line 395: Line 403:
         <br>         <br>
         <li>         <li>
-            Whenever the alarm is activated, the alarm flag bit in the DS3231 status register is switched to a 1 and needs to be reset manually by changing the bit back to a 0. The function <b><font face=Courier New>clearAlarm1()</font></b> does exactly that. It starts a transmission, sets the register pointer to the status register and resets the value. More information can be found in the datasheet on page 14.+            Whenever the alarm is activated, the alarm flag bit in the DS3231 status register is switched to a 1 and needs to be reset manually by changing the bit back to a 0. The function <b><font face="Courier New">clearAlarm1()</font></b> does exactly that. It starts a transmission, sets the register pointer to the status register and resets the value. More information can be found in the datasheet on page 14.
         </li>         </li>
         <br>         <br>
         <li>         <li>
-            The last two functions are not used in the sketch but are useful to check whether the DS3231 has a correctly configured time register. The function <b><font face=Courier New>readRTCTime()</font></b> reads the values from the register and the function <b><font face=Courier New>displayTimeSerial()</font></b> prints it to the serial monitor. In the functions pointers are used to be able to only use local instead of global variables. The local variables <b><font face=Courier New>Second</font></b>, <b><font face=Courier New>Minute</font></b>, <b><font face=Courier New>Hour</font></b> and so on are declared locally in the <b><font face=Courier New>displayTimeSerial()</font></b> function. Then their addresses are given as function argument to the <b><font face=Courier New>readRTCTime()</font></b> which gives those addresses to its own locally declared pointer variables of the same name. The pointer variables are indicated by the asterisk * next to the variable name.+            The last two functions are not used in the sketch but are useful to check whether the DS3231 has a correctly configured time register. The function <b><font face="Courier New">readRTCTime()</font></b> reads the values from the register and the function <b><font face="Courier New">displayTimeSerial()</font></b> prints it to the serial monitor. In the functions pointers are used to be able to only use local instead of global variables. The local variables <b><font face="Courier New">Second</font></b>, <b><font face="Courier New">Minute</font></b>, <b><font face="Courier New">Hour</font></b> and so on are declared locally in the <b><font face="Courier New">displayTimeSerial()</font></b> function. Then their addresses are given as function argument to the <b><font face="Courier New">readRTCTime()</font></b> which gives those addresses to its own locally declared pointer variables of the same name. The pointer variables are indicated by the asterisk * next to the variable name.
         </li>         </li>
         <li>         <li>
Line 405: Line 413:
         </li>         </li>
         <li>         <li>
-            The another transmission is started but in the slave transmitter mode using the <b><font face=Courier New><font style="color:#CD5307">Wire</font>.<font style="color:#CD5307">requestFrom</font>()</font></b> method. It needs the I2C address of the slave and the number of bytes which are requested.+            Another transmission is started but in the slave transmitter mode using the <b><font face="Courier New"><font style="color:#CD5307">Wire</font>.<font style="color:#CD5307">requestFrom</font>()</font></b> method. It needs the I2C address of the slave and the number of bytes which are requested.
         </li>         </li>
         <li>         <li>
-            The dereferencing operator, the asterisk *, is used to change the value at the address of the pointer variable, in this case the value for the local variables from the <b><font face=Courier New>displayTimeSerial()</font></b> function. As a value they get the time stored in the DS3231 time registers converted back to decimal.+            The dereferencing operator, the asterisk *, is used to change the value at the address of the pointer variable, in this case the value for the local variables from the <b><font face="Courier New">displayTimeSerial()</font></b> function. As a value they get the time stored in the DS3231 time registers converted back to decimal.
         </li>         </li>
         <br>         <br>
         <li>         <li>
-            In the <b><font face=Courier New>displayTimeSerial()</font></b> function, the local variables are created, their addresses are given to the <b><font face=Courier New>readRTCTime()</font></b> function using the referencing operator & and then their results are printed to the serial monitor+            In the <b><font face="Courier New">displayTimeSerial()</font></b> function, the local variables are created, their addresses are given to the <b><font face="Courier New">readRTCTime()</font></b> function using the referencing operator & and then their results are printed to the serial monitor
         </li>                 </li>        
     </ol>     </ol>
Line 418: Line 426:
 </html> </html>
  
 +==== 4.3 Results ====
 +
 +When uploading the sketch to the Arduino after connecting it according to the setup, the time of the module is set to Friday, 24th of July 2020, 10:15:00 which can be checked by calling the <html><b><span><font face="Courier New">displaySerialTime()</font></span></b></html> function. The alarm register is set to 12:30:00 and day/date 12 is chosen. Here it only makes sense if the alarm is not configured to match the days because a week does not have 12 days.
 +
 +In the example the setting <html><b><span><font face="Courier New">ALARM_ONCE_PER_SECOND</font></span></b></html> is chosen which means that non of the alarm registers are matched to the time registers, it just gives a signal every second which can be seen by the LED switching on and off in 1 second intervals.
 +
 +The 1 second intervals are of course only chosen to check whether the alarm works properly. As said, the ESP32 is to wake up once an hour, take measurements, transmit the data and go back to sleep afterwards. Therefore, for the final application, the setting <html><b><span><font face="Courier New">ALARM_SECONDS_MINUTES_MATCH </font></span></b></html>  will be chosen. The minutes and seconds from the alarm register match exactly once per hour, so the alarm rate is correct.
 +
 +Furthermore, the time in the alarm register will be set to 0 minutes and 0 seconds, such that the interrupt occurs with the beginning of every new hour, if the time registers are configured correctly.
 +
 +After programming the alarm and time registers, most of the code will not be needed anymore and can be left out of the final sketch. The ESP32 will only need the I2C library, an interrupt service routine to wake it up, and the <html><b><span><font face="Courier New">clearAlarm1()</font></span></b></html> function to reset the alarm flag.
 +
 +<html>
 +  <center>
 +    <span>
 +    <a href="javascript:self.scrollTo(0,0)"; onmouseover="style.color='green'";>
 +      <span style="color:#2E71B8"; onmouseover="style.color='green'"; onmouseout="style.color='#2E71B8'";>
 +        Back to the top &#10548
 +      </span>
 +    </a>
 +    </span>
 +  </center>
 +</html>
amc2020/group_n/ds3231rtc.1595756757.txt.gz · Last modified: 2021/08/24 17:34 (external edit)