Cours:TP printempsM4209 TP 6c Corr : Différence entre versions

De troyesGEII
Aller à : navigation, rechercher
m
m
Ligne 1 : Ligne 1 :
 +
<accesscontrol>Acces:Prof</accesscontrol>
  
 
Ceci est le corrigé du TP [https://fr.wikiversity.org/wiki/Very_High_Speed_Integrated_Circuit_Hardware_Description_Language/Travail_pratique/TPs_ATTiny861_avec_Altera#TP6c_:_R.C3.A9alisation_du_r.C3.A9glage_de_l.27heure_de_r.C3.A9veil_par_le_processeur Réalisation du réglage de l'heure réveil par le processeur].
 
Ceci est le corrigé du TP [https://fr.wikiversity.org/wiki/Very_High_Speed_Integrated_Circuit_Hardware_Description_Language/Travail_pratique/TPs_ATTiny861_avec_Altera#TP6c_:_R.C3.A9alisation_du_r.C3.A9glage_de_l.27heure_de_r.C3.A9veil_par_le_processeur Réalisation du réglage de l'heure réveil par le processeur].

Version du 20 mars 2018 à 13:47

Il s’agit d’une page protégée.

Ceci est le corrigé du TP Réalisation du réglage de l'heure réveil par le processeur.

Puisqu'il s'agit d'un processeur, nous donnons trois fichiers de correction :

  • fichier microcontroleur.vhd
  • fichier lcd16x2_ctrl_demo.vhd
  • un fichier d'exemple d'utilisation en C

Fichier microcontroleur.vhd

----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    08:57:48 08/26/2014 
-- Design Name: 
-- Module Name:    microcontroleur - microcontroleur_architecture 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity microcontroleur is
    Port ( clk : in  STD_LOGIC;
           Rst : in  STD_LOGIC;
			  sw : in STD_LOGIC_VECTOR (7 downto 0);
			  In_PINB : in STD_LOGIC_VECTOR (7 downto 0);
           Led : out  STD_LOGIC_VECTOR (7 downto 0);
           lcd_e  : out std_logic;
           lcd_rs : out std_logic;
           lcd_rw : out std_logic;
           lcd_db : out std_logic_vector(7 downto 4)
			  );
end entity microcontroleur;

architecture microcontroleur_architecture of microcontroleur is
--Registres et PORTs de l'ATTiny861
constant OCR1A : std_logic_vector(5 downto 0) := "101101";
constant OCR1B : std_logic_vector(5 downto 0) := "101100";
constant PORTA : std_logic_vector(5 downto 0) := "011011";
constant DDRA : std_logic_vector(5 downto 0) := "011010";
constant PINA : std_logic_vector(5 downto 0) := "011001";
constant PORTB : std_logic_vector(5 downto 0) := "011000";
constant DDRB : std_logic_vector(5 downto 0) := "010111";
constant PINB : std_logic_vector(5 downto 0) := "010110";
constant ADCH : std_logic_vector(5 downto 0) := "000101";
constant ADCL : std_logic_vector(5 downto 0) := "000100";
--Registres non présents dans l'ATTiny861
constant UDR : std_logic_vector(5 downto 0) := "000011";
constant UCSRA : std_logic_vector(5 downto 0) := "000010";
constant UCSRB : std_logic_vector(5 downto 0) := "000001";
	component mcu_core is
		Port (
			Clk	: in std_logic;
			Rst	: in std_logic; -- Reset core when Rst='1'
			En		: in std_logic; -- CPU stops when En='0', could be used to slow down cpu to save power
			-- PM
			PM_A		: out std_logic_vector(15 downto 0);
			PM_Drd	: in std_logic_vector(15 downto 0);
			-- DM
			DM_A		: out std_logic_vector(15 downto 0); -- 0x00 - xxxx
			DM_Areal	: out std_logic_vector(15 downto 0); -- 0x60 - xxxx (same as above + io-adr offset)
			DM_Drd	: in std_logic_vector(7 downto 0);
			DM_Dwr	: out std_logic_vector(7 downto 0);
			DM_rd		: out std_logic;
			DM_wr		: out std_logic;
			-- IO
			IO_A		: out std_logic_vector(5 downto 0); -- 0x00 - 0x3F
			IO_Drd	: in std_logic_vector(7 downto 0);
			IO_Dwr	: out std_logic_vector(7 downto 0);
			IO_rd		: out std_logic;
			IO_wr		: out std_logic;
			-- OTHER
		   OT_FeatErr	: out std_logic; -- Feature error! (Unhandled part of instruction)
		   OT_InstrErr	: out std_logic -- Instruction error! (Unknown instruction)
		);
	end component mcu_core;
	--PM
	component pm  is
		Port (
				Clk	: in std_logic;
				rst	: in std_logic; -- Reset when Rst='1'
				-- PM
				PM_A		: in std_logic_vector(15 downto 0);
				PM_Drd	: out std_logic_vector(15 downto 0)
		);
	end component pm;	

  component dm is
    Port ( clk : in  STD_LOGIC;
           addr : in  STD_LOGIC_VECTOR (15 downto 0);
           dataread : out  STD_LOGIC_VECTOR (7 downto 0);
           datawrite : in  STD_LOGIC_VECTOR (7 downto 0);
           rd : in  STD_LOGIC;
           wr : in  STD_LOGIC);
  end component dm;
  
  component lcd16x2_ctrl_demo is
  port (
    clk    : in  std_logic;
	 Armkey    : in std_logic;
	 HHMMAlarm : in std_logic_vector(15 downto 0);
	 HHMMCourante : out std_logic_vector(15 downto 0);
    lcd_e  : out std_logic;
    lcd_rs : out std_logic;
    lcd_rw : out std_logic;
    lcd_db : out std_logic_vector(7 downto 4);
	 led_out : out std_logic);
end component lcd16x2_ctrl_demo;

	signal PM_A		: std_logic_vector(15 downto 0);
	signal PM_Drd	: std_logic_vector(15 downto 0);
	-- DM
	signal DM_A			: std_logic_vector(15 downto 0); -- 0x00 - xxxx
	signal DM_Areal	: std_logic_vector(15 downto 0); -- 0x60 - xxxx (same as above + io-adr offset)
	signal DM_Drd		: std_logic_vector(7 downto 0);
	signal DM_Dwr		: std_logic_vector(7 downto 0);
	signal DM_rd		: std_logic;
	signal DM_wr		: std_logic;
	-- IO
	signal IO_A		: std_logic_vector(5 downto 0); -- 0x00 - 0x3F
	signal IO_Drd	: std_logic_vector(7 downto 0);
	signal IO_Dwr	: std_logic_vector(7 downto 0);
	signal IO_rd	: std_logic;
	signal IO_wr	: std_logic;

	signal IO_DrdA	: std_logic_vector(7 downto 0);
	signal IO_DrdB	: std_logic_vector(7 downto 0);

	signal s_HHMMAlarm, s_HHMMCourante : std_logic_vector(15 downto 0);
	       
begin

	core : mcu_core Port map (
		Clk	=> clk,
		Rst	=> Rst,
		En		=> '1',
		-- PM
		PM_A		=> PM_A,
		PM_Drd	=> PM_Drd,
		-- DM
		DM_A		=> DM_A,
		DM_Areal	=> DM_Areal,
		DM_Drd	=> DM_Drd,
		DM_Dwr	=> DM_Dwr,
		DM_rd		=> DM_rd,
		DM_wr		=> DM_wr,
		-- IO
		IO_A		=> IO_A,
		IO_Drd	=> IO_Drd,
		IO_Dwr	=> IO_Dwr,
		IO_rd		=> IO_rd,
		IO_wr		=> IO_wr,
		-- OTHER
		OT_FeatErr => open,
		OT_InstrErr	=> open
	);

	prgmem : pm port map (
			Clk	=> clk,
			Rst	=> '0',
			-- PM
			PM_A		=> PM_A,
			PM_Drd	=> PM_Drd
	);
	
	datamem : dm port map (
           clk => clk,
           addr => DM_A,
           dataread  => DM_Drd,
           datawrite => DM_Dwr,
           rd => DM_rd, 
           wr =>	DM_wr
	);
	
	lcdmanager: lcd16x2_ctrl_demo port map (
    clk    => clk,
	 Armkey    => '0',
	 HHMMAlarm => s_HHMMAlarm,
	 HHMMCourante => s_HHMMCourante,
    lcd_e  => lcd_e,
    lcd_rs => lcd_rs,
    lcd_rw => lcd_rw,
    lcd_db => lcd_db,
	 led_out => open);
	
	-- IO write process
--
    iowr: process(CLK)
    begin
        if (rising_edge(CLK)) then
            if (IO_wr = '1') then
                case IO_A is
		 -- addresses for tiny861 device (use io.h).
       --
                    when PORTA  => -- PORTA=X"1B" (0X3B)
                                   Led <= IO_Dwr;
		              when  PORTB => -- PORTB=X"18" (0X38)
			                          s_HHMMAlarm(7 downto 0) <= IO_Dwr;
                    when  DDRB => -- PORTB=X"17" (0X37)
			                          s_HHMMAlarm(15 downto 8) <= IO_Dwr;
--                    when  ADCL => -- PORTB=X"18" (0X38)
--			                          s_HHMMAlarm(23 downto 16) <= IO_Dwr;
--                    when  ADCH => -- PORTB=X"17" (0X37)
--			                          s_HHMMAlarm(31 downto 24) <= IO_Dwr;												  
                    when others =>
                end case;
            end if;
        end if;
    end process;
	 
-- IO read process
--
    iord: process(IO_rd,IO_A,In_PINB,sw)
    begin
        -- addresses for tinyX6 device (use iom8.h).
        --
		  if IO_rd = '1' then
          case IO_A is
			   when  PINA => IO_Drd <= sw;  -- PINA=X"19" (0X39)
            when  PINB => IO_Drd <= In_PINB;  -- PINB=X"16" (0X36)
				when  PORTB => IO_Drd <= s_HHMMCourante(7 downto 0);  -- PORTB=X"18" (0X38)
				when  DDRB => IO_Drd <= s_HHMMCourante(15 downto 8);  -- PINB=X"17" (0X37)
            when others => IO_Drd <= X"AA";
          end case;
		  end if;
    end process;

end microcontroleur_architecture;

Fichier "lcd16x2_ctrl_demo.vhd"

-------------------------------------------------------------------------------
-- Title      : Synthesizable demo for design "lcd16x2_ctrl"
-- Project    : 
-------------------------------------------------------------------------------
-- File       : lcd16x2_ctrl_tb.vhd
-- Author     :   <stachelsau@T420>
-- Company    : 
-- Created    : 2012-07-28
-- Last update: 2012-07-29
-- Platform   : 
-- Standard   : VHDL'93/02
-------------------------------------------------------------------------------
-- Description: This demo writes writes a "hello world" to the display and
-- interchanges both lines periodically.
-------------------------------------------------------------------------------
-- Copyright (c) 2012 
-------------------------------------------------------------------------------
-- Revisions  :
-- Date        Version  Author  Description
-- 2012-07-28  1.0      stachelsau      Created
-------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;

-------------------------------------------------------------------------------

entity lcd16x2_ctrl_demo is
  port (
    clk    : in  std_logic;
	 Armkey    : in std_logic;
	 HHMMAlarm : in std_logic_vector(15 downto 0);
	 HHMMCourante : out std_logic_vector(15 downto 0);
    lcd_e  : out std_logic;
    lcd_rs : out std_logic;
    lcd_rw : out std_logic;
    lcd_db : out std_logic_vector(7 downto 4);
	 led_out : out std_logic);

end entity lcd16x2_ctrl_demo;

-------------------------------------------------------------------------------

architecture behavior of lcd16x2_ctrl_demo is
  component CounterBCD is
    port( EN: in std_logic;
 	   Clock: in std_logic;
 	   Reset: in std_logic;
	   ENO : out std_logic;
 	   Output: out std_logic_vector(3 downto 0));
  end component CounterBCD;
  
  component CounterModulo6 is
    port( EN: in std_logic;
 	   Clock: in std_logic;
 	   Reset: in std_logic;
	   ENO : out std_logic;
 	   Output: out std_logic_vector(3 downto 0));
  end component CounterModulo6;
  
  component SequSonnerie IS
  PORT(                  
        clock,Key,Trip,ena :IN std_logic;
        Ring :OUT std_logic
        );
  END component SequSonnerie;
  -- 
  signal timer : natural range 0 to 5000000 := 0;
  signal eno10Hz, s_eno, s_eno2, s_eno3 : std_logic := '0';
  signal line1 : std_logic_vector(127 downto 0);
  signal line2 : std_logic_vector(127 downto 0);
  signal s_data16 :  std_logic_vector(15 downto 0);
  signal s_eno2_heure : std_logic_vector(16 downto 8);
  signal s_reset : std_logic;
  signal egalite : std_logic;
  
  -- component generics
  constant CLK_PERIOD_NS : positive := 20;  -- 50 Mhz

  -- component ports
  signal rst          : std_logic;
  signal line1_buffer : std_logic_vector(127 downto 0);
  signal line2_buffer : std_logic_vector(127 downto 0);

begin  -- architecture behavior

  -- component instantiation
  DUT : entity work.lcd16x2_ctrl
    generic map (
      CLK_PERIOD_NS => CLK_PERIOD_NS)
    port map (
      clk          => clk,
      rst          => rst,
      lcd_e        => lcd_e,
      lcd_rs       => lcd_rs,
      lcd_rw       => lcd_rw,
      lcd_db       => lcd_db,
      line1_buffer => line1_buffer,
      line2_buffer => line2_buffer);

  rst <= '0';

  -- see the display's datasheet for the character map
  line1(127 downto 120) <= X"20"; 
  line1(119 downto 112) <= X"20";
  line1(111 downto 104) <= X"20";  
  line1(103 downto 96)  <= X"20";  
  line1(95 downto 88)   <= X"20";  
  line1(87 downto 84)   <= X"3";
  line1(83 downto 80)   <= s_data16(15 downto 12);
  line1(79 downto 76)   <= X"3";
  line1(75 downto 72)   <= s_data16(11 downto 8);
  line1(71 downto 64)   <= X"3A"; 
  line1(63 downto 60)   <= X"3";
  line1(59 downto 56)   <= s_data16(7 downto 4); 
  line1(55 downto 52)   <= X"3";
  line1(51 downto 48)   <= s_data16(3 downto 0);  
  line1(47 downto 40)   <= X"20";  
  line1(39 downto 32)   <= X"20";  
  line1(31 downto 24)   <= X"20";  
  line1(23 downto 16)   <= X"20";  
  line1(15 downto 8)    <= X"20";
  line1(7 downto 0)     <= X"20";

  line2(127 downto 120) <= X"20";
  line2(119 downto 112) <= X"20";
  line2(111 downto 104) <= X"20";
  line2(103 downto 96)  <= X"20";
  line2(95 downto 88)   <= X"20";
  line2(87 downto 84)   <= X"3";
  line2(83 downto 80)   <= HHMMAlarm(15 downto 12);
  line2(79 downto 76)   <= X"3";
  line2(75 downto 72)   <= HHMMAlarm(11 downto 8);
  line2(71 downto 64)   <= X"3A"; 
  line2(63 downto 60)   <= X"3";
  line2(59 downto 56)   <= HHMMAlarm(7 downto 4); 
  line2(55 downto 52)   <= X"3";
  line2(51 downto 48)   <= HHMMAlarm(3 downto 0);  
  line2(47 downto 40)   <= X"20";
  line2(39 downto 32)   <= X"20";
  line2(31 downto 24)   <= X"20";
  line2(23 downto 16)   <= X"20";
  line2(15 downto 8)    <= X"20";
  line2(7 downto 0)     <= X"20";

  line1_buffer <= line1; -- when switch_lines = '1' else line1;
  line2_buffer <= line2; -- when switch_lines = '1' else line2;

  -- timer 10 Hz
  process(clk)
  begin
    if rising_edge(clk) then
      if timer = 0 then
        timer <= 5000000;
      else
        timer <= timer - 1;
      end if;
    end if;
      
  end process;
  eno10Hz <= '1' when timer = 0 else
            '0';
				
				
  MNUnit: CounterBCD port map( 
    EN => eno10Hz,
 	 Clock => clk,
 	 Reset => '0',
	 ENO => s_eno,
 	 Output => s_data16(3 downto 0));
  MNDiz: CounterModulo6 port map( 
    EN => s_eno,
 	 Clock => clk,
 	 Reset => '0',
	 ENO => s_eno2,
 	 Output => s_data16(7 downto 4));
  HHUnit: CounterBCD port map( 
    EN => s_eno2,
 	 Clock => clk,
 	 Reset => s_reset,
	 ENO => s_eno3,
 	 Output => s_data16(11 downto 8));
  HHDiz: CounterBCD port map( 
    EN => s_eno3,
 	 Clock => clk,
 	 Reset => s_reset,
	 ENO => open,
 	 Output => s_data16(15 downto 12));	 	 				
-- reset quand 23 est detecte	par rebouclage
    s_eno2_heure <= s_eno2 & s_data16(15 downto 8);
    with s_eno2_heure select
	   s_reset <= '1' when "100100011",
                 '0' when others;
  egalite <= '1' when HHMMAlarm = s_data16 else
            '0';
  SequenceurPourSonnerie:	SequSonnerie PORT MAP(                  
        clock => clk,
		  Key=> ArmKey,
		  Trip => egalite,
		  ena => eno10Hz,
        Ring => led_out
        );
	HHMMCourante <= s_data16;	  
end architecture behavior;

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity CounterBCD is
   port( EN: in std_logic;
 	 Clock: in std_logic;
 	 Reset: in std_logic;
	 ENO : out std_logic;
 	 Output: out std_logic_vector(3 downto 0));
end CounterBCD;
 
architecture Behavioral of CounterBCD is
   signal cmpt: std_logic_vector(3 downto 0);
	signal s_en_cmpt: std_logic_vector(4 downto 0);
begin   process(Clock,Reset)
   begin
      if(rising_edge(Clock)) then
		  if Reset='1' then
         cmpt <= "0000";
 	      elsif EN='1' then
	         if cmpt="1001" then
	            cmpt<="0000";
	         else
	           cmpt <= cmpt + 1;
	         end if;
         end if;
      end if;
   end process;
   Output <= cmpt;
	s_en_cmpt <= en & cmpt;
   with s_en_cmpt select
     ENO <= '1' when "11001",
            '0' when others;
end Behavioral;

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
-- pour les dizaines de minutes
entity CounterModulo6 is
   port( EN: in std_logic;
 	 Clock: in std_logic;
 	 Reset: in std_logic;
	 ENO : out std_logic;
 	 Output: out std_logic_vector(3 downto 0));
end CounterModulo6;
 
architecture Behavioral of CounterModulo6 is
   signal cmpt: std_logic_vector(3 downto 0);
	signal s_en_cmpt: std_logic_vector(4 downto 0);
begin   process(Clock,Reset)
   begin
      if(rising_edge(Clock)) then
		  if Reset='1' then
         cmpt <= "0000";
 	      elsif EN='1' then
	         if cmpt="0101" then
	            cmpt<="0000";
	         else
	           cmpt <= cmpt + 1;
	         end if;
         end if;
      end if;
   end process;
   Output <= cmpt;
	s_en_cmpt <= en & cmpt;
   with s_en_cmpt select
     ENO <= '1' when "10101",
            '0' when others;
end Behavioral;

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
ENTITY SequSonnerie IS
  PORT(                  
        clock,Key,Trip,ena :IN std_logic;
        Ring :OUT std_logic
        );
END SequSonnerie;
ARCHITECTURE arch_SequSonnerie  OF SequSonnerie IS
  TYPE typetat IS (Armed, Off, Ringing); 
  SIGNAL etatp, etatf : typetat;
  BEGIN
-- partie séquentielle
    PROCESS (clock) BEGIN  -- 1er process
	 IF Clock ='1' AND Clock'EVENT THEN
	   IF ena = '1' then
            etatp <= etatf;
		END IF;
     END IF;
    END PROCESS;
    PROCESS(etatp) BEGIN --2eme process
        CASE etatp IS
             WHEN Off => IF key ='1' THEN etatf <= Armed; 
                         ELSE etatf <= Off;
                      END IF;  
             WHEN Armed => IF Key = '0' THEN 
                            etatf <= Off;
	                   ELSIF Trip ='1' THEN 
                             etatf <= Ringing;
	                   ELSE etatf <= Armed;
	                  END IF; 
             WHEN Ringing => IF Key ='0' THEN 
                                 etatf <= Off; 
                            ELSE etatf <= Ringing;
			    END IF; 
	        END CASE;
    END PROCESS;
-- partie combinatoire
   Ring <= '1' WHEN etatp=Ringing ELSE
           '0';
END arch_SequSonnerie;

Fichier d'exemple en C

#include "avr/io.h" 
#undef F_CPU 
#define F_CPU 16000000UL 
#include "util/delay.h" 

//#include <stdio.h>
//#include <string.h>

/*#define UCSRB	_SFR_IO8(0x01) 
#define UCSRA	_SFR_IO8(0x02) 
#define UDR	_SFR_IO8(0x03)
// UCSRA
#define RXC 7
#define TXC 6
#define UDRE 5
//UCSRB
#define RXEN 4
#define TXEN 3
*/
void incrementBCD(uint16_t *cnt);
void decrementBCD(uint16_t *cnt);
void incrementHHMM(uint16_t *hh_mm);
void decrementHHMM(uint16_t *hh_mm);
 
int main (void) {
   uint8_t ch=128, switchs;
   uint16_t heure_courante, heure_reveil = 0; 
   while(1) { 
   // echo simple
   //  PORTA = ch;
     ch >>= 1; 
     if (ch == 0) ch = 128;
     switchs = PINA;
     if ((switchs & 0x03) == 3)
       decrementHHMM(&heure_reveil);
     if ((switchs & 0x03) == 2)
       incrementHHMM(&heure_reveil);

     PORTB = heure_reveil & 0x00FF;
     DDRB = (heure_reveil & 0xFF00)>>8;
     heure_courante = DDRB;
     heure_courante <<= 8;
     heure_courante += PORTB;
     if ((switchs & 0x04) == 0x04) {
        // a remplacer par == mais pour nos tests rapides ...
        if (heure_courante > heure_reveil) 
          PORTA = 0xFF;
     } else 
        PORTA = 0; 
     _delay_ms(300); // on défiler les valeurs     
   } 
   return 0; 
 }

void incrementBCD(uint16_t *cnt) { 
  (*cnt)++;    
  if ((*cnt & 0x000F) > 0x0009) *cnt += 6; 
  if ((*cnt & 0x00F0) > 0x0090) *cnt += 0x0060;
  if ((*cnt & 0x00F0) > 0x0900) *cnt += 0x0600; 
  if ((*cnt & 0x00F0) > 0x9000) *cnt += 0x6000; 
} 

void decrementBCD(uint16_t *cnt) { 
  (*cnt)--;    
  if ((*cnt & 0x000F) == 0x000F) *cnt -= 6; 
  if ((*cnt & 0x00F0) == 0x00F0) *cnt -= 0x0060; 
  if ((*cnt & 0x0F00) == 0x0F00) *cnt -= 0x0600; 
  if ((*cnt & 0xF000) == 0xF000) *cnt -= 0x6000; 
}

void incrementHHMM(uint16_t *hh_mm) {
  (*hh_mm)++;
      if ((*hh_mm & 0x000F) > 0x0009)
      *hh_mm += 0x0006;
      if ((*hh_mm & 0x00F0) > 0x0050)
      *hh_mm += 0x00A0;
      if ((*hh_mm & 0x0F00) > 0x0900)
      *hh_mm += 0x0600;
      if ((*hh_mm & 0xFF00) > 0x2300)
      *hh_mm = 0x0000;
}

void decrementHHMM(uint16_t *hh_mm) {
  (*hh_mm)--;
      if ((*hh_mm & 0x000F) == 0x000F)
      *hh_mm -= 0x0006;
      if ((*hh_mm & 0x00F0) == 0x00F0)
      *hh_mm -= 0x00A0;
      if ((*hh_mm & 0x0F00) == 0x0F00)
      *hh_mm -= 0x0600;
      if ((*hh_mm & 0xFFFF) > 0x2359)
      *hh_mm = 0x2359;
}