Răsfoiți Sursa

update morse (#1)

 update morse
zhkag 2 ani în urmă
părinte
comite
ab671212f5
10 a modificat fișierele cu 656 adăugiri și 46 ștergeri
  1. 97 0
      README.md
  2. 17 5
      SConscript
  3. 14 2
      inc/morse.h
  4. 67 0
      samples/key/morse-key-example.c
  5. 0 21
      samples/morse-key-example.c
  6. 29 0
      samples/tpad/morse-tpad-example.c
  7. 238 0
      samples/tpad/tpad.c
  8. 54 0
      samples/tpad/tpad.h
  9. 71 18
      src/morse.c
  10. 69 0
      src/morse_shell.c

+ 97 - 0
README.md

@@ -0,0 +1,97 @@
+# morse
+
+## 介绍
+
+摩尔斯电码(英语:Morse code)是一种时通时断的信号代码,通过不同的排列顺序来表达不同的英文字母、数字和标点符号。
+
+摩尔斯电码是一种早期的数字化通信形式,但是它不同于现代只使用0和1两种状态的二进制代码,它的代码包括五种:
+
+1. 点(·):1
+2. 划(-):111
+3. 字符内部的停顿(在点和划之间):0
+4. 字符之间的停顿:000
+5. 单词之间的停顿:0000000
+
+### 时间控制和表示方法
+
+有两种“符号”用来表示字符:点(·)和划(-),或叫“滴”(dit)和“答”(dah)。点的长度决定了发报的速度,并且被当作发报时间参考。下面是时间控制的图示:
+
+```text
+-- --- ·-· ··· ·       -·-· --- -·· ·
+M   O   R   S  E        C    O   D  E
+```
+
+这里,“-”表示划,“·”表示点。这是上面消息的准确发报时间(=表示有信号,.代表无信号,每个为一个点的长度):
+
+```text
+===.===...===.===.===...=.===.=...=.=.=...=.......===.=.===.=...===.===.===...===.=.=...=
+   ^           ^        ^       ^             ^
+   |           划       点       |          单词间隔
+点划间隔                      字符间隔
+```
+
+划一般是三个点的长度;点划之间的间隔是一个点的长度;字符之间的间隔是三个点的长度;单词之间的间隔是七个点的长度。
+
+初学者往往被教导发送点划间隔短小、短而快的字符,并且在符号和单词之间夸大间隔时间。比较起来,这种方式更加容易学会。
+
+熟悉摩尔斯码的人之间经常像这样说话或拼写(其中,“长音 / Dah”是发“awe”的音):
+
+  --     ---       ·-·      ···    · /    -·-·        ---      -··   ·
+ DahDah DahDahDah DiDahDit DiDiDit Dit, DahDiDahDit DahDahDah DahDiDi Di.
+
+### 基础拉丁字母
+
+| 字符 | 代码 | 字符 | 代码 | 字符 | 代码 | 字符 | 代码 | 字符 | 代码 | 字符 | 代码 | 字符 | 代码 |
+| :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
+| A | `·-` | B | `-···` | C | `-·-·` | D | `-··` | E | `·` | F | `··-·` | G | `--·` |
+| H | `····` | I | `··` | J | `·---` | K | `-·-` | L | `·-··` | M | `--` | N | `-·` |
+| O | `---` | P | `·--·` | Q | `--·-` | R | `·-·` | S | `···` | T | `-` | U | `··-` |
+| V | `···-` | W | `·--` | X | `-··-` | Y | `-·--` | Z | `--··` |   |   |   |   |
+
+### 数字
+
+| 字符 | 代码 | 字符 | 代码 | 字符 | 代码 | 字符 | 代码 | 字符 | 代码 |
+| :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
+| 1 | `·----` | 2 | `··---` | 3 | `···--` | 4 | `····-` | 5 | `·····` |
+| 6 | `-····` | 7 | `--···` | 8 | `---··` | 9 | `----·` | 0 | `-----` |
+
+### 标点符号
+
+| 字符 | 代码 | 字符 | 代码 | 字符 | 代码 | 字符 | 代码 | 字符 | 代码 | 字符 | 代码 |
+| :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
+| . | `·-·-·-` | : | `---···` | , | `--··--` | ; | `-·-·-·` | ? | `··--··` | = | `-···-` |
+| ' | `·----·` | / | `-··-·` | ! | `-·-·--` | - | `-····-` | _ | `··--·-` | " | `·-··-·` |
+| ( | `-·--·` | ) | `-·--·-` | $ | `···-··-` | & | `·-···` | @ | `·--·-·` | + | `·-·-·` |
+
+### 特殊符号
+
+| 符号 | 代码 | 意义 | shell 中意义|
+| :-: | :-: | :-: | :-: |
+| HH | `········` | 表示“有错,从上一字重新开始”。 | 退格(\b) |
+| SK | `···-·-` | 表示终止(联系结束)。 | 回车(\n) |
+
+## 使用 Morse
+
+### API 介绍
+
+1. 初始化 morse
+
+    ```c
+    void morse_init();
+    ```
+
+2. morse 信号输入
+
+    ```c
+    void morse_input(rt_bool_t flag);
+    ```
+
+通过 morse_input 来实现信号的输入功能,可以接收任何形式的信号输入,通过判断输入 1 的时间来完成对 morse code 的解析。
+
+通过使能 PKG_USING_MORSE_SHELL 可以实现输入命令并运行 shell 指令的目的
+
+## 联系方式 & 感谢
+
+- 维护:zhkag
+- 主页:https://github.com/zhkag/morse
+- 邮箱:zhkag@foxmail.com

+ 17 - 5
SConscript

@@ -1,13 +1,25 @@
 from building import *
 
 cwd     = GetCurrentDir()
-src     = Glob('src/*.c')
+src     = Glob('src/morse.c')
 CPPPATH    = [cwd + '/inc']
+    
+if GetDepend(['PKG_USING_MORSE_SHELL']):
+	src += Split("""
+	src/morse_shell.c
+	""")
 
-if GetDepend(['PKG_USING_MORSE_KEY_SAMPLE']):
-    src += Split("""
-    samples/morse-key-example.c
-    """)
+if GetDepend(['PKG_USING_MORSE_SAMPLE']):
+	if GetDepend(['PKG_USING_MORSE_KEY_SAMPLE']):
+		src += Split("""
+		samples/morse-key-example.c
+		""")
+	if GetDepend(['PKG_USING_MORSE_TPAD_SAMPLE']):
+		CPPPATH += [cwd + '/samples/tpad']
+		src += Split("""
+		samples/tpad/tpad.c
+		samples/tpad/morse-tpad-example.c
+		""")
 
 group = DefineGroup('morse', src, depend = ['PKG_USING_MORSE'], CPPPATH = CPPPATH)
 

+ 14 - 2
inc/morse.h

@@ -2,12 +2,24 @@
 #define __MORSE_H__
 #include <rtthread.h>
 
+#ifndef PKG_USING_MORSE_DI_DA_SEPARATE
+#define PKG_USING_MORSE_DI_DA_SEPARATE    150
+#endif
+
+#ifndef PKG_USING_MORSE_INTERCHAR
+#define PKG_USING_MORSE_INTERCHAR    300
+#endif
+
 void dida_add(rt_bool_t flag);
 void dida_clean();
-char morse_analysis(rt_uint8_t value);
-static void morse_timeout(void *parameter);
+char morse_analysis(rt_uint16_t value);
+void morse_timeout(void *parameter);
 void morse_timer_start(rt_int32_t ms);
 void morse_input(rt_bool_t flag);
 void morse_init();
 
+#ifdef PKG_USING_MORSE_SHELL
+rt_uint8_t morse_getc();
+#endif
+
 #endif

+ 67 - 0
samples/key/morse-key-example.c

@@ -0,0 +1,67 @@
+#include <rtthread.h>
+#include <rtdevice.h>
+#include <board.h>
+#include <morse.h>
+#include "drv_common.h"
+#include "shell.h"
+
+#define USER_KEY GET_PIN(D, 10) // GET_PIN(H,4)
+
+void irq_callback()
+{
+    morse_input(!rt_pin_read(USER_KEY));
+}
+
+struct morse_shell
+{
+    char line[FINSH_CMD_SIZE + 1];
+    rt_uint16_t line_position;
+};
+
+void morse_thread_entry(void *parameter)
+{
+    int ch;
+    struct morse_shell shell;
+    memset(shell.line, 0, sizeof(shell.line));
+    while (1)
+    {
+        ch = morse_getc();
+        if (ch < 0)
+        {
+            continue;
+        }
+
+        if (ch == '\0' || ch == 0xFF)
+            continue;
+
+        if (ch == '\r' || ch == '\n')
+        {
+            rt_kprintf("\n");
+            msh_exec(shell.line, shell.line_position);
+            rt_kprintf(FINSH_PROMPT);
+            memset(shell.line, 0, sizeof(shell.line));
+            shell.line_position = 0;
+            continue;
+        }
+
+        shell.line[shell.line_position] = ch;
+        rt_kprintf("%c", ch);
+        ch = 0;
+        shell.line_position++;
+    }
+}
+
+int morse_key_example(void)
+{
+    rt_thread_t tid;
+    rt_pin_mode(USER_KEY, PIN_MODE_INPUT_PULLUP);
+    rt_pin_attach_irq(USER_KEY, PIN_IRQ_MODE_RISING_FALLING, irq_callback, RT_NULL);
+    rt_pin_irq_enable(USER_KEY, PIN_IRQ_ENABLE);
+    morse_init();
+    tid = rt_thread_create("mshell", morse_thread_entry, RT_NULL, 4096, 20, 10);
+
+    if (tid != NULL)
+        rt_thread_startup(tid);
+}
+
+INIT_APP_EXPORT(morse_key_example);

+ 0 - 21
samples/morse-key-example.c

@@ -1,21 +0,0 @@
-#include <rtthread.h>
-#include <rtdevice.h>
-#include <morse.h>
-#include "drv_common.h"
-
-#define USER_KEY GET_PIN(H,4)
-
-void irq_callback()
-{
-    morse_input(!rt_pin_read(USER_KEY));
-}
-
-int morse_key_example(void)
-{
-    rt_pin_mode(USER_KEY, PIN_MODE_INPUT_PULLUP);
-    rt_pin_attach_irq(USER_KEY, PIN_IRQ_MODE_RISING_FALLING, irq_callback, RT_NULL);
-    rt_pin_irq_enable(USER_KEY, PIN_IRQ_ENABLE);
-    morse_init();
-}
-
-INIT_APP_EXPORT(morse_key_example);

+ 29 - 0
samples/tpad/morse-tpad-example.c

@@ -0,0 +1,29 @@
+
+
+#include <rtthread.h>
+#include <board.h>
+#include <morse.h>
+#include <tpad.h>
+
+void morse_input_entry(void *parameter)
+{
+    while (1)
+    {
+        morse_input(tpad_scan(1));
+        rt_thread_mdelay(10);
+    }
+}
+
+int morse_tpad_example(void)
+{
+    rt_thread_t tid;
+    tpad_init(8);                           /* 初始化触摸按键 */
+    morse_init();
+    tid = rt_thread_create("morse_tpad_example", morse_input_entry, RT_NULL, 4096, 20, 10);
+
+    if (tid != NULL)
+        rt_thread_startup(tid);
+    return RT_EOK;
+}
+
+INIT_APP_EXPORT(morse_tpad_example);

+ 238 - 0
samples/tpad/tpad.c

@@ -0,0 +1,238 @@
+/**
+ ****************************************************************************************************
+ * @file        tpad.c
+ * @author      正点原子团队(ALIENTEK)
+ * @version     V1.0
+ * @date        2021-10-15
+ * @brief       电容触摸按键(TPAD) 驱动代码
+ * @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
+ ****************************************************************************************************
+ * @attention
+ *
+ * 实验平台:正点原子 探索者 F407开发板
+ * 在线视频:www.yuanzige.com
+ * 技术论坛:www.openedv.com
+ * 公司网址:www.alientek.com
+ * 购买地址:openedv.taobao.com
+ *
+ * 修改说明
+ * V1.0 20211015
+ * 第一次发布
+ *
+ ****************************************************************************************************
+ */
+
+#include "tpad.h"
+/******************************************************************************************/
+/* 空载的时候(没有手按下),计数器需要的时间
+ * 这个值应该在每次开机的时候被初始化一次
+ */
+volatile uint16_t g_tpad_default_val = 0; /* 空载的时候(没有手按下),计数器需要的时间 */
+
+/*定时器输入边沿捕获*/
+static TIM_HandleTypeDef g_timx_cap_chy_handler; /* 定时器x句柄 */
+static TIM_IC_InitTypeDef g_timx_ic_cap_chy_handler;
+
+/**
+ * @brief       初始化触摸按键
+ * @param       psc     : 分频系数(值越小, 越灵敏, 最小值为: 1)
+ * @retval      0, 初始化成功; 1, 初始化失败;
+ */
+uint8_t tpad_init(uint16_t psc)
+{
+    uint16_t buf[10];
+    uint16_t temp;
+    uint8_t j, i;
+
+    tpad_timx_cap_init(TPAD_ARR_MAX_VAL, psc - 1); /* 以Ft / (psc - 1) Mhz的频率计数 @Ft = 定时器工作频率 */
+
+    for (i = 0; i < 10; i++) /* 连续读取10次 */
+    {
+        buf[i] = tpad_get_val();
+        rt_thread_mdelay(10);
+    }
+
+    for (i = 0; i < 9; i++) /* 排序 */
+    {
+        for (j = i + 1; j < 10; j++)
+        {
+            if (buf[i] > buf[j]) /* 升序排列 */
+            {
+                temp = buf[i];
+                buf[i] = buf[j];
+                buf[j] = temp;
+            }
+        }
+    }
+
+    temp = 0;
+
+    for (i = 2; i < 8; i++) /* 取中间的6个数据进行平均 */
+    {
+        temp += buf[i];
+    }
+
+    g_tpad_default_val = temp / 6;
+    rt_kprintf("g_tpad_default_val:%d\r\n", g_tpad_default_val);
+
+    if (g_tpad_default_val > (uint16_t)TPAD_ARR_MAX_VAL / 2)
+    {
+        return 1; /* 初始化遇到超过TPAD_ARR_MAX_VAL/2的数值,不正常! */
+    }
+
+    return 0;
+}
+
+/**
+ * @brief       复位TPAD
+ *   @note      我们将TPAD按键看做是一个电容, 当手指按下/不按下时容值有变化
+ *              该函数将GPIO设置成推挽输出, 然后输出0, 进行放电, 然后再设置
+ *              GPIO为浮空输入, 等待外部大电阻慢慢充电
+ * @param       无
+ * @retval      无
+ */
+void tpad_reset(void)
+{
+    GPIO_InitTypeDef gpio_init_struct;
+
+    gpio_init_struct.Pin = TPAD_GPIO_PIN;          /* 输入捕获的GPIO口 */
+    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;   /* 复用推挽输出 */
+    gpio_init_struct.Pull = GPIO_PULLDOWN;         /* 下拉 */
+    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
+    HAL_GPIO_Init(TPAD_GPIO_PORT, &gpio_init_struct);
+
+    HAL_GPIO_WritePin(TPAD_GPIO_PORT, TPAD_GPIO_PIN, GPIO_PIN_RESET); /* TPAD引脚输出0, 放电 */
+    rt_thread_mdelay(5);
+
+    g_timx_cap_chy_handler.Instance->SR = 0;  /* 清除标记 */
+    g_timx_cap_chy_handler.Instance->CNT = 0; /* 归零 */
+
+    gpio_init_struct.Pin = TPAD_GPIO_PIN;             /* 输入捕获的GPIO口 */
+    gpio_init_struct.Mode = GPIO_MODE_AF_PP;          /* 复用推挽输出 */
+    gpio_init_struct.Pull = GPIO_NOPULL;              /* 不带上下拉 */
+    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;    /* 高速 */
+    gpio_init_struct.Alternate = TPAD_GPIO_AF;        /* PA5复用为TIM2通道1 */
+    HAL_GPIO_Init(TPAD_GPIO_PORT, &gpio_init_struct); /* TPAD引脚浮空输入 */
+}
+
+/**
+ * @brief       得到定时器捕获值
+ *   @note      如果超时, 则直接返回定时器的计数值
+ *              我们定义超时时间为: TPAD_ARR_MAX_VAL - 500
+ * @param       无
+ * @retval      捕获值/计数值(超时的情况下返回)
+ */
+uint16_t tpad_get_val(void)
+{
+    uint32_t flag = (TPAD_TIMX_CAP_CHY == TIM_CHANNEL_1) ? TIM_FLAG_CC1 : (TPAD_TIMX_CAP_CHY == TIM_CHANNEL_2) ? TIM_FLAG_CC2
+                                                                      : (TPAD_TIMX_CAP_CHY == TIM_CHANNEL_3)   ? TIM_FLAG_CC3
+                                                                                                               : TIM_FLAG_CC4;
+
+    tpad_reset();
+
+    while (__HAL_TIM_GET_FLAG(&g_timx_cap_chy_handler, flag) == RESET) /* 等待通道CHY捕获上升沿 */
+    {
+        if (g_timx_cap_chy_handler.Instance->CNT > TPAD_ARR_MAX_VAL - 500)
+        {
+            return g_timx_cap_chy_handler.Instance->CNT; /* 超时了,直接返回CNT的值 */
+        }
+    }
+
+    return TPAD_TIMX_CAP_CHY_CCRX; /* 返回捕获/比较值 */
+}
+
+/**
+ * @brief       读取n次, 取最大值
+ * @param       n       :连续获取的次数
+ * @retval      n次读数里面读到的最大读数值
+ */
+uint16_t tpad_get_maxval(uint8_t n)
+{
+    uint16_t temp = 0;
+    uint16_t maxval = 0;
+
+    while (n--)
+    {
+        temp = tpad_get_val(); /* 得到一次值 */
+
+        if (temp > maxval)
+        {
+            maxval = temp;
+        }
+    }
+
+    return maxval;
+}
+
+/**
+ * @brief       扫描触摸按键
+ * @param       mode :扫描模式
+ *   @arg       0, 不支持连续触发(按下一次必须松开才能按下一次);
+ *   @arg       1, 支持连续触发(可以一直按下)
+ * @retval      0, 没有按下; 1, 有按下;
+ */
+uint8_t tpad_scan(uint8_t mode)
+{
+    static uint8_t keyen = 0; /* 0, 可以开始检测;  > 0, 还不能开始检测; */
+    uint8_t res = 0;
+    uint8_t sample = 3; /* 默认采样次数为3次 */
+    uint16_t rval;
+
+    if (mode)
+    {
+        sample = 6; /* 支持连按的时候,设置采样次数为6次 */
+        keyen = 0;  /* 支持连按, 每次调用该函数都可以检测 */
+    }
+
+    rval = tpad_get_maxval(sample);
+
+    if (rval > (g_tpad_default_val + TPAD_GATE_VAL)) /* 大于tpad_default_val + TPAD_GATE_VAL,有效 */
+    {
+        if (keyen == 0)
+        {
+            res = 1; /* keyen==0, 有效 */
+        }
+
+        //      rt_kprintf("r:%d\r\n", rval);   /* 输出计数值, 调试的时候才用到 */
+        keyen = 3; /* 至少要再过3次之后才能按键有效 */
+    }
+
+    if (keyen)
+        keyen--;
+
+    return res;
+}
+
+/**
+ * @brief       触摸按键输入捕获设置
+ * @param       arr     :自动重装值
+ * @param       psc     :时钟预分频数
+ * @retval      无
+ */
+void tpad_timx_cap_init(uint32_t arr, uint16_t psc)
+{
+    GPIO_InitTypeDef gpio_init_struct;
+    TPAD_GPIO_CLK_ENABLE();         /* TPAD引脚 时钟使能 */
+    TPAD_TIMX_CAP_CHY_CLK_ENABLE(); /* 定时器 时钟使能 */
+
+    gpio_init_struct.Pin = TPAD_GPIO_PIN;             /* 输入捕获的GPIO口 */
+    gpio_init_struct.Mode = GPIO_MODE_AF_PP;          /* 复用推挽输出 */
+    gpio_init_struct.Pull = GPIO_NOPULL;              /* 不带上下拉 */
+    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;    /* 概述 */
+    gpio_init_struct.Alternate = TPAD_GPIO_AF;        /* PA5复用为TIM2_CH1 */
+    HAL_GPIO_Init(TPAD_GPIO_PORT, &gpio_init_struct); /* TPAD引脚复用 */
+
+    g_timx_cap_chy_handler.Instance = TPAD_TIMX_CAP;                    /* 定时器2 */
+    g_timx_cap_chy_handler.Init.Prescaler = psc;                        /* 定时器分频 */
+    g_timx_cap_chy_handler.Init.CounterMode = TIM_COUNTERMODE_UP;       /* 向上计数模式 */
+    g_timx_cap_chy_handler.Init.Period = arr;                           /* 自动重装载值 */
+    g_timx_cap_chy_handler.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; /* 时钟分频因子 */
+    HAL_TIM_IC_Init(&g_timx_cap_chy_handler);
+
+    g_timx_ic_cap_chy_handler.ICPolarity = TIM_ICPOLARITY_RISING;                                     /* 上升沿捕获 */
+    g_timx_ic_cap_chy_handler.ICSelection = TIM_ICSELECTION_DIRECTTI;                                 /* 映射到TI1上 */
+    g_timx_ic_cap_chy_handler.ICPrescaler = TIM_ICPSC_DIV1;                                           /* 配置输入分频,不分频 */
+    g_timx_ic_cap_chy_handler.ICFilter = 0;                                                           /* 配置输入滤波器,不滤波 */
+    HAL_TIM_IC_ConfigChannel(&g_timx_cap_chy_handler, &g_timx_ic_cap_chy_handler, TPAD_TIMX_CAP_CHY); /* 配置TIM2通道1 */
+    HAL_TIM_IC_Start(&g_timx_cap_chy_handler, TPAD_TIMX_CAP_CHY);                                     /* 使能输入捕获和定时器 */
+}

+ 54 - 0
samples/tpad/tpad.h

@@ -0,0 +1,54 @@
+
+
+#ifndef __TPAD_H
+#define __TPAD_H
+
+#include <rtthread.h>
+#include <board.h>
+#include <drivers/pin.h>
+
+/******************************************************************************************/
+/* TPAD 引脚 及 定时器 定义 */
+
+/* 我们使用定时器的输入捕获功能, 对TPAD进行检测
+ * 这里的输入捕获使用定时器TIM2_CH1, 捕获TPAD按键的输入
+ */
+#define TPAD_GPIO_PORT GPIOA
+#define TPAD_GPIO_PIN GPIO_PIN_5
+#define TPAD_GPIO_CLK_ENABLE()        \
+    do                                \
+    {                                 \
+        __HAL_RCC_GPIOA_CLK_ENABLE(); \
+    } while (0)                    /* PA口时钟使能 */
+#define TPAD_GPIO_AF GPIO_AF1_TIM2 /*端口复用为TIM2通道1*/
+
+#define TPAD_TIMX_CAP TIM2
+#define TPAD_TIMX_CAP_CHY TIM_CHANNEL_1   /* 通道Y,  1<= Y <=4 */
+#define TPAD_TIMX_CAP_CHY_CCRX TIM2->CCR1 /* 通道Y的捕获/比较寄存器 */
+#define TPAD_TIMX_CAP_CHY_CLK_ENABLE() \
+    do                                 \
+    {                                  \
+        __HAL_RCC_TIM2_CLK_ENABLE();   \
+    } while (0) /* TIM5 时钟使能 */
+
+/******************************************************************************************/
+
+/* 触摸的门限值, 也就是必须大于 g_tpad_default_val + TPAD_GATE_VAL
+ * 才认为是有效触摸, 改大 TPAD_GATE_VAL, 可以降低灵敏度, 反之, 则可以提高灵敏度
+ * 根据实际需求, 选择合适的 TPAD_GATE_VAL 即可
+ */
+#define TPAD_GATE_VAL 100           /* 触摸的门限值, 也就是必须大于 g_tpad_default_val + TPAD_GATE_VAL, 才认为是有效触摸 */
+#define TPAD_ARR_MAX_VAL 0xFFFFFFFF /* 最大的ARR值, 一般设置为定时器的ARR最大值 */
+
+/* 接口函数, 可以在其他.c调用 */
+uint8_t tpad_init(uint16_t psc); /* TPAD 初始化 函数 */
+uint8_t tpad_scan(uint8_t mode); /* TPAD 扫描 函数 */
+
+extern volatile uint16_t g_tpad_default_val; /* 空载的时候(没有手按下),计数器需要的时间 */
+
+void tpad_reset(void);                               /* 复位 */
+uint16_t tpad_get_val(void);                         /* 得到定时器捕获值 */
+uint16_t tpad_get_maxval(uint8_t n);                 /* 读取n次, 获取最大值 */
+void tpad_timx_cap_init(uint32_t arr, uint16_t psc); /* 定时器输入捕获初始化 */
+
+#endif

+ 71 - 18
src/morse.c

@@ -1,23 +1,63 @@
 #include <morse.h>
 
+#define RT_DA 1
+#define RT_DI 0
+
+static rt_timer_t morse_timer;
 rt_tick_t millisecond = 0;
 rt_bool_t morse_flag = RT_FALSE;
-rt_uint8_t morse_value = 0x01;
+rt_uint16_t morse_value = 0x01;
+rt_uint8_t morse_char = 0xff;
+rt_uint8_t morse_num_max = 0;
 
-char morse_array[255] = {0,0,'e','t','i','a','n','m','s','u','r','w','d','k',
-        'g','o','h','v','f',0,'l',0,'p','j','b','x','c','y','z','q',0,0,
-        '5','4',0,'3',0,0,0,'2',0,0,0,0,0,'1','6',0,0,0,0,0,0,0,'7',0,0,0,'8',0,'9','0'};
+typedef struct {
+    rt_uint16_t id;
+    rt_uint8_t value;
+} morse_equivalent;
 
-#define RT_DA 1
-#define RT_DI 0
+static const morse_equivalent morse_equivalent_type[] = {
+        { 0b00010, 'e' }, { 0b00011, 't' }, { 0b00100, 'i' }, { 0b00101, 'a' }, { 0b00110, 'n' },
+        { 0b00111, 'm' }, { 0b01000, 's' }, { 0b01001, 'u' }, { 0b01010, 'r' }, { 0b01011, 'w' },
+        { 0b01100, 'd' }, { 0b01101, 'k' }, { 0b01110, 'g' }, { 0b01111, 'o' }, { 0b10000, 'h' },
+        { 0b10001, 'v' }, { 0b10010, 'f' }, { 0b10100, 'l' }, { 0b10110, 'p' }, { 0b10111, 'j' },
+        { 0b11000, 'b' }, { 0b11001, 'x' }, { 0b11010, 'c' }, { 0b11011, 'y' }, { 0b11100, 'z' },
+        { 0b11101, 'q' },
 
-static rt_timer_t morse_timer;
-static void morse_timeout(void *parameter)
+        { 0b100000, '5' }, { 0b100001, '4' }, { 0b100011, '3' }, { 0b100111, '2' }, { 0b101000, '&' },
+        { 0b101010, '+' }, { 0b101111, '1' }, { 0b110000, '6' }, { 0b110001, '=' }, { 0b110010, '/' },
+        { 0b110110, '(' }, { 0b111000, '7' }, { 0b111100, '8' }, { 0b111110, '9' }, { 0b111111, '0' },
+
+        { 0b1000101, '\n' }, { 0b1001100, '?' }, { 0b1001101, '_' }, { 0b1010010, '"' }, { 0b1010101, '.' }, { 0b1011010, '@' },
+        { 0b1011110, '\'' }, { 0b1100001, '-' }, { 0b1101010, ';' }, { 0b1101011, '!' }, { 0b1101101, ')' }, { 0b1110011, ',' }, { 0b1111000, ':' },
+
+        { 0b10001001, '$' }, { 0b100000000, '\b' },
+
+        { 0b1, '\0' },
+};
+
+void morse_timeout(void *parameter)
 {
-    rt_kprintf("%c",morse_analysis(morse_value));
+    morse_char = morse_analysis(morse_value);
+#ifndef PKG_USING_MORSE_SHELL
+    rt_kprintf("%c",morse_char);
+#endif
     dida_clean();
 }
 
+#ifdef PKG_USING_MORSE_SHELL
+rt_uint8_t morse_getc()
+{
+    int ch;
+    while (morse_char == 0xff)
+    {
+        rt_thread_mdelay(100);
+    }
+    ch = morse_char;
+    morse_char = 0xff;
+    return ch;
+}
+#endif
+
 void morse_timer_start(rt_int32_t ms)
 {
     rt_tick_t tick = rt_tick_from_millisecond(ms);
@@ -38,29 +78,39 @@ void dida_clean()
     morse_value = 0x01;
 }
 
-char morse_analysis(rt_uint8_t value)
+char morse_analysis(rt_uint16_t value)
 {
-    return morse_array[value];
+    for (rt_uint8_t middle, start = 0, end = morse_num_max; start <= end;) {
+        middle = (start + end) / 2;
+        if(morse_equivalent_type[middle].id == value)
+            return morse_equivalent_type[middle].value;
+        else if (morse_equivalent_type[middle].id > value)
+            end = middle - 1;
+        else
+            start = middle + 1;
+    }
+    return 0x00;
 }
 
 void morse_input(rt_bool_t flag)
 {
-    if(morse_flag != flag)
+    if (morse_flag != flag)
     {
         rt_tick_t interval = rt_tick_get_millisecond() - millisecond;
         millisecond = rt_tick_get_millisecond();
-        if(flag)
+        if (flag)
         {
             rt_timer_stop(morse_timer);
         }
         else
         {
-            if(interval <= 150)
+            if (interval <= PKG_USING_MORSE_DI_DA_SEPARATE)
                 dida_add(RT_DI);
-            else{
+            else
+            {
                 dida_add(RT_DA);
             }
-            morse_timer_start(300);
+            morse_timer_start(PKG_USING_MORSE_INTERCHAR);
         }
         morse_flag = flag;
     }
@@ -68,7 +118,10 @@ void morse_input(rt_bool_t flag)
 
 void morse_init()
 {
+    rt_uint8_t var = 0;
+    for (; morse_equivalent_type[var].id != 0b1; ++var);
+    morse_num_max = var;
     morse_timer = rt_timer_create("morse", morse_timeout,
-                             RT_NULL,  0,
-                             RT_TIMER_FLAG_ONE_SHOT);
+                                  RT_NULL, 0,
+                                  RT_TIMER_FLAG_ONE_SHOT);
 }

+ 69 - 0
src/morse_shell.c

@@ -0,0 +1,69 @@
+#include <rtthread.h>
+#include <board.h>
+#include <morse.h>
+#include <shell.h>
+#include <msh.h>
+#include <string.h>
+
+struct morse_shell
+{
+    char line[FINSH_CMD_SIZE + 1];
+    rt_uint16_t line_position;
+};
+
+void morse_shell_entry(void *parameter)
+{
+    int ch;
+    struct morse_shell shell;
+    memset(shell.line, 0, sizeof(shell.line));
+    while (1)
+    {
+        ch = morse_getc();
+        if (ch < 0)
+        {
+            continue;
+        }
+
+        if (ch == '\0' || ch == 0xFF)
+            continue;
+
+        if (ch == '\r' || ch == '\n')
+        {
+            rt_kprintf("\n");
+            msh_exec(shell.line, shell.line_position);
+            rt_kprintf(FINSH_PROMPT);
+            memset(shell.line, 0, sizeof(shell.line));
+            shell.line_position = 0;
+            continue;
+        }
+
+        /* handle backspace key */
+        else if (ch == 0x7f || ch == 0x08)
+        {
+            if (shell.line_position == 0)
+                continue;
+
+            shell.line_position--;
+            rt_kprintf("\b \b");
+            shell.line[shell.line_position] = 0;
+            continue;
+        }
+
+        shell.line[shell.line_position] = ch;
+        rt_kprintf("%c", ch);
+        ch = 0;
+        shell.line_position++;
+    }
+}
+
+int morse_key_example(void)
+{
+    rt_thread_t tid;
+    tid = rt_thread_create("mshell", morse_shell_entry, RT_NULL, 4096, 20, 10);
+
+    if (tid != NULL)
+        rt_thread_startup(tid);
+    return RT_EOK;
+}
+
+INIT_APP_EXPORT(morse_key_example);