diff --git a/include/gpio.h b/include/gpio.h
index 9031bf666bc01fd74840f84397d4e0da3a6d13ce..8fea176627702e56e994c46522bdd37bbf40c203 100644
--- a/include/gpio.h
+++ b/include/gpio.h
@@ -8,8 +8,13 @@ typedef enum {NORTH_LED,SOUTH_LED,EAST_LED,WEST_LED} led_t;
 typedef enum {NORTH_PB,SOUTH_PB,EAST_PB,WEST_PB} pushbutton_t;
 
 void gpio_init(void);
+// LED functions
 void gpio_set_led(led_t led_id);
 void gpio_clear_led(led_t led_id); 
+void gpio_toggle_led(led_t led_id); 
 void gpio_blink_led(led_t led_id, int16_t period_ms);
+// Pushbuttons functions
+uint8_t gpio_is_pushbutton_pressed(pushbutton_t pb_id);
+void gpio_set_pushbutton_callback(pushbutton_t pb_id,void (*callback)(void));
 
 #endif
diff --git a/src/bioloid_stm32.c b/src/bioloid_stm32.c
index 3fb2476a3f87cb8443e8f3aab408892d899cded8..c9917ba99788c9e79e18a3e9c6ecc1a34015465d 100644
--- a/src/bioloid_stm32.c
+++ b/src/bioloid_stm32.c
@@ -30,6 +30,11 @@ uint8_t read_operation(uint8_t address, uint8_t length, uint8_t *data)
   }
 }
 
+void test_led(void)
+{
+  gpio_toggle_led(NORTH_LED);
+}
+
 int32_t main(void)
 {
   uint8_t inst_packet[1024];
@@ -70,10 +75,9 @@ int32_t main(void)
   else
     GPIO_ResetBits(GPIOD,GPIO_Pin_12);
   
-  gpio_blink_led(NORTH_LED,1000);
-  gpio_blink_led(SOUTH_LED,2000);
-  gpio_blink_led(EAST_LED,3000);
-  gpio_blink_led(WEST_LED,4000);
+  gpio_set_pushbutton_callback(NORTH_PB,test_led);
+  gpio_blink_led(EAST_LED,2000);
+  gpio_blink_led(WEST_LED,1000);
   while(1)                             /* main function does not return */
   {
     if(dyn_slave_is_packet_ready())// check if a new instruction packet has been received
diff --git a/src/gpio.c b/src/gpio.c
index 9aa05b7b7666b0f60cf9ea3d8eca65962a025ee9..625c0a23dd646d4d4f8219923df81c6f5a127752 100644
--- a/src/gpio.c
+++ b/src/gpio.c
@@ -40,49 +40,95 @@
 #define PUSH_BUTTON4_GPIO_PORT    GPIOC                       
 #define PUSH_BUTTON4_SOURCE       GPIO_PinSource15
 
-#define GPIO_TIMER                TIM2
-#define GPIO_TIMER_CLK            RCC_APB1Periph_TIM2
-#define GPIO_TIMER_IRQn           TIM2_IRQn
-#define GPIO_TIMER_IRQHandler     TIM2_IRQHandler
+#define GPO_TIMER                 TIM2
+#define GPO_TIMER_CLK             RCC_APB1Periph_TIM2
+#define GPO_TIMER_IRQn            TIM2_IRQn
+#define GPO_TIMER_IRQHandler      TIM2_IRQHandler
+
+#define GPI_TIMER                 TIM3
+#define GPI_TIMER_CLK             RCC_APB1Periph_TIM3
+#define GPI_TIMER_IRQn            TIM3_IRQn
+#define GPI_TIMER_IRQHandler      TIM3_IRQHandler
 
 // private variables
+// LED blink periods
 __IO uint16_t north_led_period;
 __IO uint16_t south_led_period;
 __IO uint16_t east_led_period;
 __IO uint16_t west_led_period;
+// Pushbuttons callbacks
+void (*north_pb_callback)(void);
+void (*south_pb_callback)(void);
+void (*east_pb_callback)(void);
+void (*west_pb_callback)(void);
 
 // IRQ hanfler functions
-void TIM2_IRQHandler(void)
+void GPI_TIMER_IRQHandler(void)
 {
   uint16_t capture;
+  static uint8_t north_pb_last=Bit_SET,south_pb_last=Bit_SET,east_pb_last=Bit_SET,west_pb_last=Bit_SET;
+  uint8_t north_pb_new,south_pb_new,east_pb_new,west_pb_new;
 
-  if(TIM_GetITStatus(GPIO_TIMER, TIM_IT_CC1)!=RESET)
+  if(TIM_GetITStatus(GPI_TIMER, TIM_IT_CC1)!=RESET)
   {
-    TIM_ClearITPendingBit(GPIO_TIMER,TIM_IT_CC1);
+    TIM_ClearITPendingBit(GPI_TIMER,TIM_IT_CC1);
+    capture = TIM_GetCapture1(GPI_TIMER);
+    TIM_SetCompare1(GPI_TIMER, capture + 10);
+    /* check all the pushbuttons */
+    north_pb_new=GPIO_ReadInputDataBit(PUSH_BUTTON1_GPIO_PORT,PUSH_BUTTON1_PIN);
+    if(north_pb_last==Bit_SET && north_pb_new==Bit_RESET)
+      if(north_pb_callback!=0)  
+        north_pb_callback();
+    north_pb_last=north_pb_new;
+    south_pb_new=GPIO_ReadInputDataBit(PUSH_BUTTON2_GPIO_PORT,PUSH_BUTTON2_PIN);
+    if(south_pb_last==Bit_SET && south_pb_new==Bit_RESET)
+      if(south_pb_callback!=0)  
+        south_pb_callback();
+    south_pb_last=south_pb_new;
+    east_pb_new=GPIO_ReadInputDataBit(PUSH_BUTTON3_GPIO_PORT,PUSH_BUTTON3_PIN);
+    if(east_pb_last==Bit_SET && east_pb_new==Bit_RESET)
+      if(east_pb_callback!=0)  
+        east_pb_callback();
+    east_pb_last=east_pb_new;
+    west_pb_new=GPIO_ReadInputDataBit(PUSH_BUTTON4_GPIO_PORT,PUSH_BUTTON4_PIN);
+    if(west_pb_last==Bit_SET && west_pb_new==Bit_RESET)
+      if(west_pb_callback!=0)  
+        west_pb_callback();
+    west_pb_last=west_pb_new;
+  }
+}
+
+void GPO_TIMER_IRQHandler(void)
+{
+  uint16_t capture;
+
+  if(TIM_GetITStatus(GPO_TIMER, TIM_IT_CC1)!=RESET)
+  {
+    TIM_ClearITPendingBit(GPO_TIMER,TIM_IT_CC1);
     GPIO_ToggleBits(LED1_GPIO_PORT,LED1_PIN);
-    capture = TIM_GetCapture1(GPIO_TIMER);
-    TIM_SetCompare1(GPIO_TIMER, capture + north_led_period);
+    capture = TIM_GetCapture1(GPO_TIMER);
+    TIM_SetCompare1(GPO_TIMER, capture + north_led_period);
   }
-  if(TIM_GetITStatus(GPIO_TIMER, TIM_IT_CC2)!=RESET)
+  if(TIM_GetITStatus(GPO_TIMER, TIM_IT_CC2)!=RESET)
   {
-    TIM_ClearITPendingBit(GPIO_TIMER,TIM_IT_CC2);
+    TIM_ClearITPendingBit(GPO_TIMER,TIM_IT_CC2);
     GPIO_ToggleBits(LED2_GPIO_PORT,LED2_PIN);
-    capture = TIM_GetCapture2(GPIO_TIMER);
-    TIM_SetCompare2(GPIO_TIMER, capture + south_led_period);
+    capture = TIM_GetCapture2(GPO_TIMER);
+    TIM_SetCompare2(GPO_TIMER, capture + south_led_period);
   }
-  if(TIM_GetITStatus(GPIO_TIMER, TIM_IT_CC3)!=RESET)
+  if(TIM_GetITStatus(GPO_TIMER, TIM_IT_CC3)!=RESET)
   {
-    TIM_ClearITPendingBit(GPIO_TIMER,TIM_IT_CC3);
+    TIM_ClearITPendingBit(GPO_TIMER,TIM_IT_CC3);
     GPIO_ToggleBits(LED3_GPIO_PORT,LED3_PIN);
-    capture = TIM_GetCapture3(GPIO_TIMER);
-    TIM_SetCompare3(GPIO_TIMER, capture + east_led_period);
+    capture = TIM_GetCapture3(GPO_TIMER);
+    TIM_SetCompare3(GPO_TIMER, capture + east_led_period);
   }
-  if(TIM_GetITStatus(GPIO_TIMER, TIM_IT_CC4)!=RESET)
+  if(TIM_GetITStatus(GPO_TIMER, TIM_IT_CC4)!=RESET)
   {
-    TIM_ClearITPendingBit(GPIO_TIMER,TIM_IT_CC4);
+    TIM_ClearITPendingBit(GPO_TIMER,TIM_IT_CC4);
     GPIO_ToggleBits(LED4_GPIO_PORT,LED4_PIN);
-    capture = TIM_GetCapture4(GPIO_TIMER);
-    TIM_SetCompare4(GPIO_TIMER, capture + west_led_period);
+    capture = TIM_GetCapture4(GPO_TIMER);
+    TIM_SetCompare4(GPO_TIMER, capture + west_led_period);
   }
 }
 
@@ -94,11 +140,12 @@ void gpio_init(void)
   GPIO_InitTypeDef  GPIO_InitStructure;
   TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
   NVIC_InitTypeDef NVIC_InitStructure;
+  TIM_OCInitTypeDef  TIM_OCInitStructure;
 
   /* enable clocks */
   RCC_AHB1PeriphClockCmd(LED1_GPIO_CLK | LED2_GPIO_CLK | LED3_GPIO_CLK | LED4_GPIO_CLK, ENABLE);
   RCC_AHB1PeriphClockCmd(PUSH_BUTTON1_GPIO_CLK | PUSH_BUTTON2_GPIO_CLK | PUSH_BUTTON3_GPIO_CLK | PUSH_BUTTON4_GPIO_CLK, ENABLE);
-  RCC_APB1PeriphClockCmd(GPIO_TIMER_CLK,ENABLE);
+  RCC_APB1PeriphClockCmd(GPO_TIMER_CLK | GPI_TIMER_CLK,ENABLE);
 
   /* GPIO Configuration */
   GPIO_InitStructure.GPIO_Pin = LED1_PIN;
@@ -133,23 +180,49 @@ void gpio_init(void)
   GPIO_InitStructure.GPIO_Pin = PUSH_BUTTON4_PIN;
   GPIO_Init(PUSH_BUTTON4_GPIO_PORT, &GPIO_InitStructure);
 
+  // initialize private variables
+  north_led_period=0;
+  south_led_period=0;
+  east_led_period=0;
+  west_led_period=0;
+  north_pb_callback=0;
+  south_pb_callback=0;
+  east_pb_callback=0;
+  west_pb_callback=0;
+
   // initialize the timer interrupts
-  NVIC_InitStructure.NVIC_IRQChannel = GPIO_TIMER_IRQn;
+  NVIC_InitStructure.NVIC_IRQChannel = GPO_TIMER_IRQn;
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+  NVIC_Init(&NVIC_InitStructure);
 
+  NVIC_InitStructure.NVIC_IRQChannel = GPI_TIMER_IRQn;
   NVIC_Init(&NVIC_InitStructure);
 
-  /* Time base configuration */
+  /* LED's timer configuration */
+  TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
+  TIM_TimeBaseStructure.TIM_Prescaler = 0;
+  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
+  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
+  TIM_TimeBaseInit(GPO_TIMER,&TIM_TimeBaseStructure);
+  TIM_Cmd(GPO_TIMER, ENABLE);
+  TIM_PrescalerConfig(GPO_TIMER, 42000, TIM_PSCReloadMode_Immediate);
+  TIM_SetClockDivision(GPO_TIMER,TIM_CKD_DIV2);
+
+  /* pushbutton timer configuration */
   TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
   TIM_TimeBaseStructure.TIM_Prescaler = 0;
   TIM_TimeBaseStructure.TIM_ClockDivision = 0;
   TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
-  TIM_TimeBaseInit(GPIO_TIMER,&TIM_TimeBaseStructure);
-  TIM_Cmd(GPIO_TIMER, ENABLE);
-  TIM_PrescalerConfig(GPIO_TIMER, 42000, TIM_PSCReloadMode_Immediate);
-  TIM_SetClockDivision(GPIO_TIMER,TIM_CKD_DIV2);
+  TIM_TimeBaseInit(GPI_TIMER,&TIM_TimeBaseStructure);
+  TIM_Cmd(GPI_TIMER, ENABLE);
+  TIM_PrescalerConfig(GPI_TIMER, 42000, TIM_PSCReloadMode_Immediate);
+  TIM_SetClockDivision(GPI_TIMER,TIM_CKD_DIV2);
+  TIM_OCInitStructure.TIM_Pulse = 10;// 10 Hz
+  TIM_OC1Init(GPI_TIMER, &TIM_OCInitStructure);
+  TIM_OC1PreloadConfig(GPI_TIMER, TIM_OCPreload_Disable);
+  TIM_ITConfig(GPI_TIMER, TIM_IT_CC1, ENABLE);
 }
 
 void gpio_set_led(led_t led_id)
@@ -190,6 +263,25 @@ void gpio_clear_led(led_t led_id)
   }
 }
 
+void gpio_toggle_led(led_t led_id)
+{
+  switch(led_id)
+  {
+    case NORTH_LED:
+      GPIO_ToggleBits(LED1_GPIO_PORT,LED1_PIN);
+      break;
+    case SOUTH_LED:
+      GPIO_ToggleBits(LED2_GPIO_PORT,LED2_PIN);
+      break;
+    case EAST_LED:
+      GPIO_ToggleBits(LED3_GPIO_PORT,LED3_PIN);
+      break;
+    case WEST_LED:
+      GPIO_ToggleBits(LED4_GPIO_PORT,LED4_PIN);
+      break;
+  }
+}
+
 void gpio_blink_led(led_t led_id, int16_t period_ms)
 {
   TIM_OCInitTypeDef  TIM_OCInitStructure;
@@ -204,48 +296,98 @@ void gpio_blink_led(led_t led_id, int16_t period_ms)
       {
         north_led_period=period_ms;
         TIM_OCInitStructure.TIM_Pulse = north_led_period;
-        TIM_OC1Init(GPIO_TIMER, &TIM_OCInitStructure);
-        TIM_OC1PreloadConfig(GPIO_TIMER, TIM_OCPreload_Disable);
-        TIM_ITConfig(GPIO_TIMER, TIM_IT_CC1, ENABLE);
+        TIM_OC1Init(GPO_TIMER, &TIM_OCInitStructure);
+        TIM_OC1PreloadConfig(GPO_TIMER, TIM_OCPreload_Disable);
+        TIM_ITConfig(GPO_TIMER, TIM_IT_CC1, ENABLE);
       }
       else
-        TIM_ITConfig(GPIO_TIMER, TIM_IT_CC1, DISABLE);
+        TIM_ITConfig(GPO_TIMER, TIM_IT_CC1, DISABLE);
       break;
     case SOUTH_LED:
       if(period_ms>1)
       {
         south_led_period=period_ms;
         TIM_OCInitStructure.TIM_Pulse = south_led_period;
-        TIM_OC2Init(GPIO_TIMER, &TIM_OCInitStructure);
-        TIM_OC2PreloadConfig(GPIO_TIMER, TIM_OCPreload_Disable);
-        TIM_ITConfig(GPIO_TIMER, TIM_IT_CC2, ENABLE);
+        TIM_OC2Init(GPO_TIMER, &TIM_OCInitStructure);
+        TIM_OC2PreloadConfig(GPO_TIMER, TIM_OCPreload_Disable);
+        TIM_ITConfig(GPO_TIMER, TIM_IT_CC2, ENABLE);
       }
       else
-        TIM_ITConfig(GPIO_TIMER, TIM_IT_CC2, DISABLE);
+        TIM_ITConfig(GPO_TIMER, TIM_IT_CC2, DISABLE);
       break;
     case EAST_LED:
       if(period_ms>1)
       {
         east_led_period=period_ms;
         TIM_OCInitStructure.TIM_Pulse = east_led_period;
-        TIM_OC3Init(GPIO_TIMER, &TIM_OCInitStructure);
-        TIM_OC3PreloadConfig(GPIO_TIMER, TIM_OCPreload_Disable);
-        TIM_ITConfig(GPIO_TIMER, TIM_IT_CC3, ENABLE);
+        TIM_OC3Init(GPO_TIMER, &TIM_OCInitStructure);
+        TIM_OC3PreloadConfig(GPO_TIMER, TIM_OCPreload_Disable);
+        TIM_ITConfig(GPO_TIMER, TIM_IT_CC3, ENABLE);
       }
       else
-        TIM_ITConfig(GPIO_TIMER, TIM_IT_CC3, DISABLE);
+        TIM_ITConfig(GPO_TIMER, TIM_IT_CC3, DISABLE);
       break;
     case WEST_LED:
       if(period_ms>1)
       {
         west_led_period=period_ms;
         TIM_OCInitStructure.TIM_Pulse = west_led_period;
-        TIM_OC4Init(GPIO_TIMER, &TIM_OCInitStructure);
-        TIM_OC4PreloadConfig(GPIO_TIMER, TIM_OCPreload_Disable);
-        TIM_ITConfig(GPIO_TIMER, TIM_IT_CC4, ENABLE);
+        TIM_OC4Init(GPO_TIMER, &TIM_OCInitStructure);
+        TIM_OC4PreloadConfig(GPO_TIMER, TIM_OCPreload_Disable);
+        TIM_ITConfig(GPO_TIMER, TIM_IT_CC4, ENABLE);
       }
       else
-        TIM_ITConfig(GPIO_TIMER, TIM_IT_CC4, DISABLE);
+        TIM_ITConfig(GPO_TIMER, TIM_IT_CC4, DISABLE);
+      break;
+  }
+}
+
+uint8_t gpio_is_pushbutton_pressed(pushbutton_t pb_id)
+{
+  switch(pb_id)
+  {
+    case NORTH_PB:
+      if(GPIO_ReadInputDataBit(PUSH_BUTTON1_GPIO_PORT,PUSH_BUTTON1_PIN)==Bit_SET)
+        return 0x01;
+      else
+        return 0x00;
+      break;
+    case SOUTH_PB:
+      if(GPIO_ReadInputDataBit(PUSH_BUTTON2_GPIO_PORT,PUSH_BUTTON2_PIN)==Bit_SET)
+        return 0x01;
+      else
+        return 0x00;
+      break;
+    case EAST_PB:
+      if(GPIO_ReadInputDataBit(PUSH_BUTTON3_GPIO_PORT,PUSH_BUTTON3_PIN)==Bit_SET)
+        return 0x01;
+      else
+        return 0x00;
+      break;
+    case WEST_PB:
+      if(GPIO_ReadInputDataBit(PUSH_BUTTON4_GPIO_PORT,PUSH_BUTTON4_PIN)==Bit_SET)
+        return 0x01;
+      else
+        return 0x00;
+      break;
+  }
+}
+
+void gpio_set_pushbutton_callback(pushbutton_t pb_id,void (*callback)(void))
+{
+  switch(pb_id)
+  {
+    case NORTH_PB:
+      north_pb_callback=callback;
+      break;
+    case SOUTH_PB:
+      south_pb_callback=callback;
+      break;
+    case EAST_PB:
+      east_pb_callback=callback;
+      break;
+    case WEST_PB:
+      west_pb_callback=callback;
       break;
   }
 }