diff --git a/esp8266/Makefile b/esp8266/Makefile
index 26b5e8626bb2d801ea7726d7d916dc3a3c508c21..9008f2036586d95f54ae21a946378eeab2333cdb 100644
--- a/esp8266/Makefile
+++ b/esp8266/Makefile
@@ -128,6 +128,7 @@ LIB_SRC_C = $(addprefix lib/,\
 	timeutils/timeutils.c \
 	utils/pyexec.c \
 	utils/pyhelp.c \
+	utils/interrupt_char.c \
 	fatfs/ff.c \
 	fatfs/option/ccsbcs.c \
 	)
diff --git a/esp8266/esp_mphal.c b/esp8266/esp_mphal.c
index b0755239fc339089fd464b2b51322c924731830b..f5e284fde654a14445053fe199d08243797b20c2 100644
--- a/esp8266/esp_mphal.c
+++ b/esp8266/esp_mphal.c
@@ -128,14 +128,6 @@ void mp_hal_delay_ms(uint32_t delay) {
     mp_hal_delay_us(delay * 1000);
 }
 
-void mp_hal_set_interrupt_char(int c) {
-    if (c != -1) {
-        mp_obj_exception_clear_traceback(MP_STATE_PORT(mp_kbd_exception));
-    }
-    extern int interrupt_char;
-    interrupt_char = c;
-}
-
 void ets_event_poll(void) {
     ets_loop_iter();
     if (MP_STATE_VM(mp_pending_exception) != NULL) {
@@ -180,7 +172,7 @@ static int call_dupterm_read(void) {
         mp_buffer_info_t bufinfo;
         mp_get_buffer_raise(MP_STATE_PORT(dupterm_arr_obj), &bufinfo, MP_BUFFER_READ);
         nlr_pop();
-        if (*(byte*)bufinfo.buf == interrupt_char) {
+        if (*(byte*)bufinfo.buf == mp_interrupt_char) {
             mp_keyboard_interrupt();
             return -2;
         }
diff --git a/esp8266/esp_mphal.h b/esp8266/esp_mphal.h
index fa52ae53a20a604ddcd76fb57e75619007791f97..7a71c0f0327cd37bb99170ba7df4dd36c0cfb8f1 100644
--- a/esp8266/esp_mphal.h
+++ b/esp8266/esp_mphal.h
@@ -28,10 +28,10 @@
 #define _INCLUDED_MPHAL_H_
 
 #include "py/ringbuf.h"
+#include "lib/utils/interrupt_char.h"
 #include "xtirq.h"
 
 void mp_keyboard_interrupt(void);
-extern int interrupt_char;
 
 struct _mp_print_t;
 // Structure for UART-only output via mp_printf()
diff --git a/esp8266/main.c b/esp8266/main.c
index 71dfeb2ac65f54cd68cbcc1cb625f1fd7b672fdc..22abb22d785d34f09c1f66c412d0a06bc8587e1a 100644
--- a/esp8266/main.c
+++ b/esp8266/main.c
@@ -141,10 +141,6 @@ mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
 }
 MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
 
-void mp_keyboard_interrupt(void) {
-    MP_STATE_VM(mp_pending_exception) = MP_STATE_PORT(mp_kbd_exception);
-}
-
 void nlr_jump_fail(void *val) {
     printf("NLR jump failed\n");
     for (;;) {
diff --git a/esp8266/uart.c b/esp8266/uart.c
index d724331c41a984685c60291a1bfe12cf644b5273..001a9c673c87ed572ababf623d53053ef56941e3 100644
--- a/esp8266/uart.c
+++ b/esp8266/uart.c
@@ -39,8 +39,6 @@ static void uart0_rx_intr_handler(void *para);
 void soft_reset(void);
 void mp_keyboard_interrupt(void);
 
-int interrupt_char;
-
 /******************************************************************************
  * FunctionName : uart_config
  * Description  : Internal used function
@@ -172,7 +170,7 @@ static void uart0_rx_intr_handler(void *para) {
 
         while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
             uint8 RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xff;
-            if (RcvChar == interrupt_char) {
+            if (RcvChar == mp_interrupt_char) {
                 mp_keyboard_interrupt();
             } else {
                 ringbuf_put(&input_buf, RcvChar);
diff --git a/lib/utils/interrupt_char.c b/lib/utils/interrupt_char.c
new file mode 100644
index 0000000000000000000000000000000000000000..3133d5c0683f721980f718f847b9b74cf44a38d9
--- /dev/null
+++ b/lib/utils/interrupt_char.c
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2016 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "py/mpstate.h"
+
+int mp_interrupt_char;
+
+void mp_hal_set_interrupt_char(int c) {
+    if (c != -1) {
+        mp_obj_exception_clear_traceback(MP_STATE_PORT(mp_kbd_exception));
+    }
+    mp_interrupt_char = c;
+}
+
+void mp_keyboard_interrupt(void) {
+    MP_STATE_VM(mp_pending_exception) = MP_STATE_PORT(mp_kbd_exception);
+}
diff --git a/lib/utils/interrupt_char.h b/lib/utils/interrupt_char.h
new file mode 100644
index 0000000000000000000000000000000000000000..ae0bf57e8a268796320e32876af5509e25893eea
--- /dev/null
+++ b/lib/utils/interrupt_char.h
@@ -0,0 +1,29 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2016 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+extern int mp_interrupt_char;
+void mp_hal_set_interrupt_char(int c);
+void mp_keyboard_interrupt(void);