返回列表 发新帖我要提问本帖赏金: 60.00元(功能说明)

[应用相关] 【每周分享】STM32F103核心板+HX1838实现红外遥控电脑

[复制链接]
 楼主| yuyy1989 发表于 2024-11-7 17:48 | 显示全部楼层 |阅读模式
<
#申请原创# #技术资源# @21小跑堂  红外遥控是利用红外光进行通信的设备,由红外LED将调制后的信号发出,由专用的红外接收头进行解调输出。红外线的波长在可见光范围外,所以人眼是看不到的。在生活中电视机空调等设备都可以用红外遥控器来控制,正好手里有个HX1838红外接收器和遥控器,想着也给电脑做个红外遥控。
用到的设备:HX1838红外接收器,红外遥控,引出USB的STM32F103核心板
微信截图_20241106182750.png 微信截图_20241107173738.png
基本原理就是用STM32F103核心板模拟USB键盘,解析HX1838收到的红外信号后转为按键命令发送给电脑
先来实现对红外信号的解析,要解析红外信号就要用到红外接收器,红外接收器是一种能够接收红外光信号并将其转换为电信号的元件。红外接收器会对接收到的红外光信号进行解析,以还原出原始的指令或数据。红外接收头通常被集成在一个元件中,内部包含光敏二极管等关键部件,以及用于信号放大、解调等功能的电路。这里用到的HX1838模块是可接收标准38KHz调制的遥控器信号,通过对进行编程,即可实现对遥控器信号的解码操作。
这套遥控套件使用的是NEC编码,关于NEC编码的介绍可以看这篇帖子 【每周分享】红外遥控中常用的NEC编码https://bbs.21ic.com/icview-3409956-1-1.html
HX1838模块接收到38KHz的红外PWM信号时输出低电平,否则输出高电平,这点和NEC编码中相反,编程时需要注意,程序通过高低电平的时间来解析红外数据。
配套遥控器的按键码
微信截图_20241106180200.png
先根据NEC编码规则写出解析红外信号的代码
  1. enum
  2. {
  3.     IR_CODE_STEP_IDLE = 0,
  4.     IR_CODE_STEP_START,
  5.     IR_CODE_STEP_DATA,
  6.     IR_CODE_STEP_STOP,
  7. };
  8. enum
  9. {
  10.     IR_CODE_FLAG_NONE = 0,
  11.     IR_CODE_FLAG_CMD,
  12.     IR_CODE_FLAG_REPEAT,
  13. };
  14. #define MAX_TIME_DIFF 60
  15. uint32_t IR_time_us = 0;
  16. uint32_t IR_H_time_us = 0;
  17. uint32_t IR_L_time_us = 0;
  18. uint8_t IR_code[4];
  19. uint8_t IR_code_index = 0;
  20. uint8_t IR_code_bit = 0;
  21. uint8_t IR_code_step = IR_CODE_STEP_IDLE;
  22. uint8_t IR_lev_last = 0;
  23. uint8_t IR_code_flag = IR_CODE_FLAG_NONE;

  24. uint8_t IRIsTimeInRange(uint32_t time,uint32_t targettime,uint32_t diff)
  25. {
  26.     if(time < targettime && targettime - time > diff)
  27.         return 0;
  28.     if(time > targettime && time - targettime > diff)
  29.         return 0;
  30.     return 1;
  31. }
  32. void IRTimeCount(uint32_t us)
  33. {
  34.     IR_time_us += us;
  35. }
  36. void IRDataProc(void)
  37. {
  38.     switch(IR_code_step)
  39.     {
  40.         case IR_CODE_STEP_IDLE:
  41.             if(IRIsTimeInRange(IR_H_time_us,9000,MAX_TIME_DIFF) != 0)
  42.             {
  43.                 IR_code_step = IR_CODE_STEP_START;
  44.                 IR_code_flag = IR_CODE_FLAG_NONE;
  45.             }
  46.             break;
  47.         case IR_CODE_STEP_START:
  48.             if(IRIsTimeInRange(IR_L_time_us,4500,MAX_TIME_DIFF) != 0)
  49.             {
  50.                 //开始指令
  51.                 memset(IR_code,0,4);
  52.                 IR_code_index = 0;
  53.                 IR_code_bit = 0;
  54.                 IR_code_step = IR_CODE_STEP_DATA;
  55.             }
  56.             else if(IRIsTimeInRange(IR_L_time_us,2250,MAX_TIME_DIFF) != 0)
  57.             {
  58.                 //重复指令
  59.                 IR_code_step = IR_CODE_STEP_STOP;
  60.                 IR_code_flag = IR_CODE_FLAG_REPEAT;
  61.             }
  62.             else
  63.             {
  64.                 IR_code_step = IR_CODE_STEP_IDLE;
  65.                 IR_code_flag = IR_CODE_FLAG_NONE;
  66.             }
  67.             break;
  68.         case IR_CODE_STEP_DATA:
  69.             if(IRIsTimeInRange(IR_H_time_us,560,MAX_TIME_DIFF) != 0)
  70.             {
  71.                 if(IRIsTimeInRange(IR_L_time_us,1690,MAX_TIME_DIFF) != 0)
  72.                 {
  73.                     IR_code[IR_code_index] |= (1<<IR_code_bit);
  74.                 }
  75.                 else if(IRIsTimeInRange(IR_L_time_us,560,MAX_TIME_DIFF) == 0)
  76.                 {
  77.                     IR_code_step = IR_CODE_STEP_IDLE;
  78.                     IR_code_flag = IR_CODE_FLAG_NONE;
  79.                 }
  80.                 IR_code_bit += 1;
  81.                 if(IR_code_bit == 8)
  82.                 {
  83.                     IR_code_bit = 0;
  84.                     IR_code_index += 1;
  85.                     if(IR_code_index == 4)
  86.                     {
  87.                         IR_code_step = IR_CODE_STEP_STOP;
  88.                         IR_code_flag = IR_CODE_FLAG_CMD;
  89.                     }
  90.                 }
  91.             }
  92.             else
  93.             {
  94.                 IR_code_step = IR_CODE_STEP_IDLE;
  95.                 IR_code_flag = IR_CODE_FLAG_NONE;
  96.             }
  97.             break;
  98.         case IR_CODE_STEP_STOP:
  99.             if(IRIsTimeInRange(IR_H_time_us,560,MAX_TIME_DIFF) != 0)
  100.             {
  101.                 //结束指令
  102.                 IR_code_step = IR_CODE_STEP_IDLE;
  103.             }
  104.             else
  105.             {
  106.                 IR_code_step = IR_CODE_STEP_IDLE;
  107.                 IR_code_flag = IR_CODE_FLAG_NONE;
  108.             }
  109.             break;
  110.         default:
  111.             IR_code_step = IR_CODE_STEP_IDLE;
  112.             break;
  113.     }
  114. }
  115. void IRIOcheck(uint8_t lev)
  116. {
  117.     if(lev != IR_lev_last)
  118.     {
  119.         IR_lev_last = lev;
  120.         if(lev == 0)
  121.         {
  122.             IR_H_time_us = IR_time_us;
  123.             if(IR_code_step == IR_CODE_STEP_IDLE || IR_code_step == IR_CODE_STEP_STOP)
  124.             {
  125.                 IRDataProc();
  126.             }
  127.         }
  128.         else
  129.         {
  130.             if(IR_code_step == IR_CODE_STEP_IDLE)
  131.             {
  132.                 IR_L_time_us = 0;
  133.             }
  134.             else
  135.             {
  136.                 IR_L_time_us = IR_time_us;
  137.                 IRDataProc();
  138.             }
  139.         }
  140.         IR_time_us = 0;
  141.     }
  142. }
通过STM32CubeMX配置一个定时器用来对高低电平进行计时,为了避免太过频繁的进入中断,这里配置的周期是20us
微信截图_20241106190803.png
在定时器中断函数里调用IRTimeCount传入参数为定时器触发的周期
  1. void TIM4_IRQHandler(void)
  2. {
  3.   /* USER CODE BEGIN TIM4_IRQn 0 */
  4.     if(LL_TIM_IsActiveFlag_UPDATE(TIM4) == SET)
  5.     {
  6.         LL_TIM_ClearFlag_UPDATE(TIM4);
  7.         IRTimeCount(20);
  8.     }
  9.   /* USER CODE END TIM4_IRQn 0 */
  10.   /* USER CODE BEGIN TIM4_IRQn 1 */

  11.   /* USER CODE END TIM4_IRQn 1 */
  12. }
配置检测红外信号的引脚,我这里使用的是PB9开启了双边沿中断
微信截图_20241106191119.png
触发中断后检测PB9的电平,需要注意的是要做取反处理
  1. uint8_t ir_pin_it_flag = 0;
  2. void EXTI9_5_IRQHandler(void)
  3. {
  4.   /* USER CODE BEGIN EXTI9_5_IRQn 0 */

  5.   /* USER CODE END EXTI9_5_IRQn 0 */
  6.   if (LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_9) != RESET)
  7.   {
  8.     LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_9);
  9.     /* USER CODE BEGIN LL_EXTI_LINE_9 */
  10.         ir_pin_it_flag = 1;
  11.     /* USER CODE END LL_EXTI_LINE_9 */
  12.   }
  13.   /* USER CODE BEGIN EXTI9_5_IRQn 1 */

  14.   /* USER CODE END EXTI9_5_IRQn 1 */
  15. }
  16. void IRAPP(void)
  17. {
  18.     if(ir_pin_it_flag != 0)
  19.     {
  20.         ir_pin_it_flag = 0;
  21.         IRIOcheck(!LL_GPIO_IsInputPinSet(IR_PIN_GPIO_Port,IR_PIN_Pin));
  22.     }
  23. }

如果不用中断就直接轮询PB9的状态
  1. void IRAPP(void)
  2. {
  3.     IRIOcheck(!LL_GPIO_IsInputPinSet(IR_PIN_GPIO_Port,IR_PIN_Pin));
  4. }

在主循环中调用IRAPP(),检测到正确的红外控制命令后IR_code_flag会被置位,先通过串口打印看看效果
  1. if(IR_code_flag == IR_CODE_FLAG_CMD)
  2. {
  3.         printf("rev ir data: %02X%02X%02X%02X\r\n",IR_code[0],IR_code[1],IR_code[2],IR_code[3]);
  4.         IR_code_flag = IR_CODE_FLAG_NONE;
  5. }
  6. else if(IR_code_flag == IR_CODE_FLAG_REPEAT)
  7. {
  8.         printf("rev ir repeat\r\n");
  9. }

微信截图_20241107105451.png

接下来实现用STM32F103模拟键盘,在STM32CubeMX中开启USBDevice
微信截图_20241106193308.png
选择HID
微信截图_20241106193404.png
生成的代码默认设备类型是鼠标,找个键盘的描述符替换掉usbd_hid.c中的鼠标描述符
  1. //#define HID_MOUSE_REPORT_DESC_SIZE    74U
  2. #define HID_MOUSE_REPORT_DESC_SIZE    63U
  3. /*修改usbd_hid.c中的报告设备描述符*/
  4. __ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END =
  5. {
  6.         0x05, 0x01, // USAGE_PAGE (Generic Desktop) //63
  7.         0x09, 0x06, // USAGE (Keyboard)
  8.         0xa1, 0x01, // COLLECTION (Application)
  9.         0x05, 0x07, // USAGE_PAGE (Keyboard)
  10.         0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
  11.         0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
  12.         0x15, 0x00, // LOGICAL_MINIMUM (0)
  13.         0x25, 0x01, // LOGICAL_MAXIMUM (1)
  14.         0x75, 0x01, // REPORT_SIZE (1)
  15.         0x95, 0x08, // REPORT_COUNT (8)
  16.         0x81, 0x02, // INPUT (Data,Var,Abs)
  17.         0x95, 0x01, // REPORT_COUNT (1)
  18.         0x75, 0x08, // REPORT_SIZE (8)
  19.         0x81, 0x03, // INPUT (Cnst,Var,Abs)
  20.         0x95, 0x05, // REPORT_COUNT (5)
  21.         0x75, 0x01, // REPORT_SIZE (1)
  22.         0x05, 0x08, // USAGE_PAGE (LEDs)
  23.         0x19, 0x01, // USAGE_MINIMUM (Num Lock)
  24.         0x29, 0x05, // USAGE_MAXIMUM (Kana)
  25.         0x91, 0x02, // OUTPUT (Data,Var,Abs)
  26.         0x95, 0x01, // REPORT_COUNT (1)
  27.         0x75, 0x03, // REPORT_SIZE (3)
  28.         0x91, 0x03, // OUTPUT (Cnst,Var,Abs)
  29.         0x95, 0x06, // REPORT_COUNT (6)
  30.         0x75, 0x08, // REPORT_SIZE (8)
  31.         0x15, 0x00, // LOGICAL_MINIMUM (0)
  32.         0x25, 0x65, // LOGICAL_MAXIMUM (101)
  33.         0x05, 0x07, // USAGE_PAGE (Keyboard)
  34.         0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
  35.         0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
  36.         0x81, 0x00, // INPUT (Data,Ary,Abs)
  37.         0xc0,       // END_COLLECTION
  38. };

文件中USBD_HID_OtherSpeedCfgDesc这两处也改掉
微信截图_20241107111521.png
看一下键盘HID消息格式
微信截图_20240703202828.png 微信截图_20240703202836.png
找一份键盘值映射代码
  1. typedef enum
  2. {
  3.     KEYBOARD_NONE = 0,
  4.     KEYBOARD_ERROR_ROLL_OVER,
  5.     KEYBOARD_POST_FAIL,
  6.     KEYBOARD_ERROR_UNDEFINED,
  7.     KEYBOARD_A,
  8.     KEYBOARD_B,
  9.     KEYBOARD_C,
  10.     KEYBOARD_D,
  11.     KEYBOARD_E,
  12.     KEYBOARD_F,
  13.     KEYBOARD_G,
  14.     KEYBOARD_H,
  15.     KEYBOARD_I,
  16.     KEYBOARD_J,
  17.     KEYBOARD_K,
  18.     KEYBOARD_L,
  19.     KEYBOARD_M,
  20.     KEYBOARD_N,
  21.     KEYBOARD_O,
  22.     KEYBOARD_P,
  23.     KEYBOARD_Q,
  24.     KEYBOARD_R,
  25.     KEYBOARD_S,
  26.     KEYBOARD_T,
  27.     KEYBOARD_U,
  28.     KEYBOARD_V,
  29.     KEYBOARD_W,
  30.     KEYBOARD_X,
  31.     KEYBOARD_Y,
  32.     KEYBOARD_Z,
  33.     KEYBOARD_1_EXCLAMATION,
  34.     KEYBOARD_2_AT,
  35.     KEYBOARD_3_NUMBER_SIGN,
  36.     KEYBOARD_4_DOLLAR,
  37.     KEYBOARD_5_PERCENT,
  38.     KEYBOARD_6_CARET,
  39.     KEYBOARD_7_AMPERSAND,
  40.     KEYBOARD_8_ASTERISK,
  41.     KEYBOARD_9_OPARENTHESIS,
  42.     KEYBOARD_0_CPARENTHESIS,
  43.     KEYBOARD_ENTER,
  44.     KEYBOARD_ESCAPE,
  45.     KEYBOARD_BACKSPACE,
  46.     KEYBOARD_TAB,
  47.     KEYBOARD_SPACEBAR,
  48.     KEYBOARD_MINUS_UNDERSCORE,
  49.     KEYBOARD_EQUAL_PLUS,
  50.     KEYBOARD_OBRACKET_AND_OBRACE,
  51.     KEYBOARD_CBRACKET_AND_CBRACE,
  52.     KEYBOARD_BACKSLASH_VERTICAL_BAR,
  53.     KEYBOARD_NONUS_NUMBER_SIGN_TILDE,
  54.     KEYBOARD_SEMICOLON_COLON,
  55.     KEYBOARD_SINGLE_AND_DOUBLE_QUOTE,
  56.     KEYBOARD_GRAVE_ACCENT_AND_TILDE,
  57.     KEYBOARD_COMMA_AND_LESS,
  58.     KEYBOARD_DOT_GREATER,
  59.     KEYBOARD_SLASH_QUESTION,
  60.     KEYBOARD_CAPS_LOCK,
  61.     KEYBOARD_F1,
  62.     KEYBOARD_F2,
  63.     KEYBOARD_F3,
  64.     KEYBOARD_F4,
  65.     KEYBOARD_F5,
  66.     KEYBOARD_F6,
  67.     KEYBOARD_F7,
  68.     KEYBOARD_F8,
  69.     KEYBOARD_F9,
  70.     KEYBOARD_F10,
  71.     KEYBOARD_F11,
  72.     KEYBOARD_F12,
  73.     KEYBOARD_PRINTSCREEN,
  74.     KEYBOARD_SCROLL_LOCK,
  75.     KEYBOARD_PAUSE,
  76.     KEYBOARD_INSERT,
  77.     KEYBOARD_HOME,
  78.     KEYBOARD_PAGEUP,
  79.     KEYBOARD_DELETE,
  80.     KEYBOARD_END1,
  81.     KEYBOARD_PAGEDOWN,
  82.     KEYBOARD_RIGHTARROW,
  83.     KEYBOARD_LEFTARROW,
  84.     KEYBOARD_DOWNARROW,
  85.     KEYBOARD_UPARROW,
  86.     KEYBOARD_KEYBOARDPAD_NUM_LOCK_AND_CLEAR,
  87.     KEYBOARD_KEYBOARDPAD_SLASH,
  88.     KEYBOARD_KEYBOARDPAD_ASTERIKS,
  89.     KEYBOARD_KEYBOARDPAD_MINUS,
  90.     KEYBOARD_KEYBOARDPAD_PLUS,
  91.     KEYBOARD_KEYBOARDPAD_ENTER,
  92.     KEYBOARD_KEYBOARDPAD_1_END,
  93.     KEYBOARD_KEYBOARDPAD_2_DOWN_ARROW,
  94.     KEYBOARD_KEYBOARDPAD_3_PAGEDN,
  95.     KEYBOARD_KEYBOARDPAD_4_LEFT_ARROW,
  96.     KEYBOARD_KEYBOARDPAD_5,
  97.     KEYBOARD_KEYBOARDPAD_6_RIGHT_ARROW,
  98.     KEYBOARD_KEYBOARDPAD_7_HOME,
  99.     KEYBOARD_KEYBOARDPAD_8_UP_ARROW,
  100.     KEYBOARD_KEYBOARDPAD_9_PAGEUP,
  101.     KEYBOARD_KEYBOARDPAD_0_INSERT,
  102.     KEYBOARD_KEYBOARDPAD_DECIMAL_SEPARATOR_DELETE,
  103.     KEYBOARD_NONUS_BACK_SLASH_VERTICAL_BAR,
  104.     KEYBOARD_APPLICATION,
  105.     KEYBOARD_POWER,
  106.     KEYBOARD_KEYBOARDPAD_EQUAL,
  107.     KEYBOARD_F13,
  108.     KEYBOARD_F14,
  109.     KEYBOARD_F15,
  110.     KEYBOARD_F16,
  111.     KEYBOARD_F17,
  112.     KEYBOARD_F18,
  113.     KEYBOARD_F19,
  114.     KEYBOARD_F20,
  115.     KEYBOARD_F21,
  116.     KEYBOARD_F22,
  117.     KEYBOARD_F23,
  118.     KEYBOARD_F24,
  119.     KEYBOARD_EXECUTE,
  120.     KEYBOARD_HELP,
  121.     KEYBOARD_MENU,
  122.     KEYBOARD_SELECT,
  123.     KEYBOARD_STOP,
  124.     KEYBOARD_AGAIN,
  125.     KEYBOARD_UNDO,
  126.     KEYBOARD_CUT,
  127.     KEYBOARD_COPY,
  128.     KEYBOARD_PASTE,
  129.     KEYBOARD_FIND,
  130.     KEYBOARD_MUTE,
  131.     KEYBOARD_VOLUME_UP,
  132.     KEYBOARD_VOLUME_DOWN,
  133.     KEYBOARD_LOCKING_CAPS_LOCK,
  134.     KEYBOARD_LOCKING_NUM_LOCK,
  135.     KEYBOARD_LOCKING_SCROLL_LOCK,
  136.     KEYBOARD_KEYBOARDPAD_COMMA,
  137.     KEYBOARD_KEYBOARDPAD_EQUAL_SIGN,
  138.     KEYBOARD_INTERNATIONAL1,
  139.     KEYBOARD_INTERNATIONAL2,
  140.     KEYBOARD_INTERNATIONAL3,
  141.     KEYBOARD_INTERNATIONAL4,
  142.     KEYBOARD_INTERNATIONAL5,
  143.     KEYBOARD_INTERNATIONAL6,
  144.     KEYBOARD_INTERNATIONAL7,
  145.     KEYBOARD_INTERNATIONAL8,
  146.     KEYBOARD_INTERNATIONAL9,
  147.     KEYBOARD_LANG1,
  148.     KEYBOARD_LANG2,
  149.     KEYBOARD_LANG3,
  150.     KEYBOARD_LANG4,
  151.     KEYBOARD_LANG5,
  152.     KEYBOARD_LANG6,
  153.     KEYBOARD_LANG7,
  154.     KEYBOARD_LANG8,
  155.     KEYBOARD_LANG9,
  156.     KEYBOARD_ALTERNATE_ERASE,
  157.     KEYBOARD_SYSREQ,
  158.     KEYBOARD_CANCEL,
  159.     KEYBOARD_CLEAR,
  160.     KEYBOARD_PRIOR,
  161.     KEYBOARD_RETURN,
  162.     KEYBOARD_SEPARATOR,
  163.     KEYBOARD_OUT,
  164.     KEYBOARD_OPER,
  165.     KEYBOARD_CLEAR_AGAIN,
  166.     KEYBOARD_CRSEL,
  167.     KEYBOARD_EXSEL,
  168.     KEYBOARD_RESERVED1,
  169.     KEYBOARD_RESERVED2,
  170.     KEYBOARD_RESERVED3,
  171.     KEYBOARD_RESERVED4,
  172.     KEYBOARD_RESERVED5,
  173.     KEYBOARD_RESERVED6,
  174.     KEYBOARD_RESERVED7,
  175.     KEYBOARD_RESERVED8,
  176.     KEYBOARD_RESERVED9,
  177.     KEYBOARD_RESERVED10,
  178.     KEYBOARD_RESERVED11,
  179.     KEYBOARD_KEYBOARDPAD_00,
  180.     KEYBOARD_KEYBOARDPAD_000,
  181.     KEYBOARD_THOUSANDS_SEPARATOR,
  182.     KEYBOARD_DECIMAL_SEPARATOR,
  183.     KEYBOARD_CURRENCY_UNIT,
  184.     KEYBOARD_CURRENCY_SUB_UNIT,
  185.     KEYBOARD_KEYBOARDPAD_OPARENTHESIS,
  186.     KEYBOARD_KEYBOARDPAD_CPARENTHESIS,
  187.     KEYBOARD_KEYBOARDPAD_OBRACE,
  188.     KEYBOARD_KEYBOARDPAD_CBRACE,
  189.     KEYBOARD_KEYBOARDPAD_TAB,
  190.     KEYBOARD_KEYBOARDPAD_BACKSPACE,
  191.     KEYBOARD_KEYBOARDPAD_A,
  192.     KEYBOARD_KEYBOARDPAD_B,
  193.     KEYBOARD_KEYBOARDPAD_C,
  194.     KEYBOARD_KEYBOARDPAD_D,
  195.     KEYBOARD_KEYBOARDPAD_E,
  196.     KEYBOARD_KEYBOARDPAD_F,
  197.     KEYBOARD_KEYBOARDPAD_XOR,
  198.     KEYBOARD_KEYBOARDPAD_CARET,
  199.     KEYBOARD_KEYBOARDPAD_PERCENT,
  200.     KEYBOARD_KEYBOARDPAD_LESS,
  201.     KEYBOARD_KEYBOARDPAD_GREATER,
  202.     KEYBOARD_KEYBOARDPAD_AMPERSAND,
  203.     KEYBOARD_KEYBOARDPAD_LOGICAL_AND,
  204.     KEYBOARD_KEYBOARDPAD_VERTICAL_BAR,
  205.     KEYBOARD_KEYBOARDPAD_LOGIACL_OR,
  206.     KEYBOARD_KEYBOARDPAD_COLON,
  207.     KEYBOARD_KEYBOARDPAD_NUMBER_SIGN,
  208.     KEYBOARD_KEYBOARDPAD_SPACE,
  209.     KEYBOARD_KEYBOARDPAD_AT,
  210.     KEYBOARD_KEYBOARDPAD_EXCLAMATION_MARK,
  211.     KEYBOARD_KEYBOARDPAD_MEMORY_STORE,
  212.     KEYBOARD_KEYBOARDPAD_MEMORY_RECALL,
  213.     KEYBOARD_KEYBOARDPAD_MEMORY_CLEAR,
  214.     KEYBOARD_KEYBOARDPAD_MEMORY_ADD,
  215.     KEYBOARD_KEYBOARDPAD_MEMORY_SUBTRACT,
  216.     KEYBOARD_KEYBOARDPAD_MEMORY_MULTIPLY,
  217.     KEYBOARD_KEYBOARDPAD_MEMORY_DIVIDE,
  218.     KEYBOARD_KEYBOARDPAD_PLUSMINUS,
  219.     KEYBOARD_KEYBOARDPAD_CLEAR,
  220.     KEYBOARD_KEYBOARDPAD_CLEAR_ENTRY,
  221.     KEYBOARD_KEYBOARDPAD_BINARY,
  222.     KEYBOARD_KEYBOARDPAD_OCTAL,
  223.     KEYBOARD_KEYBOARDPAD_DECIMAL,
  224.     KEYBOARD_KEYBOARDPAD_HEXADECIMAL,
  225.     KEYBOARD_RESERVED12,
  226.     KEYBOARD_RESERVED13,
  227.     KEYBOARD_LEFTCONTROL,
  228.     KEYBOARD_LEFTSHIFT,
  229.     KEYBOARD_LEFTALT,
  230.     KEYBOARD_LEFT_GUI,
  231.     KEYBOARD_RIGHTCONTROL,
  232.     KEYBOARD_RIGHTSHIFT,
  233.     KEYBOARD_RIGHTALT,
  234.     KEYBOARD_RIGHT_GUI,
  235. } USBH_HID_KEYBOARD_VALUE_T;
将遥控器的数字键按照原本的数字输入,方向键控制光标方向,OK键回车,*键退格,#键del
  1. uint8_t IRCode2Key(uint8_t ircode)
  2. {
  3.     switch(ircode)
  4.     {
  5.         case 0x45:
  6.             return KEYBOARD_1_EXCLAMATION;
  7.         case 0x46:
  8.             return KEYBOARD_2_AT;
  9.         case 0x47:
  10.             return KEYBOARD_3_NUMBER_SIGN;
  11.         case 0x44:
  12.             return KEYBOARD_4_DOLLAR;
  13.         case 0x40:
  14.             return KEYBOARD_5_PERCENT;
  15.         case 0x43:
  16.             return KEYBOARD_6_CARET;
  17.         case 0x07:
  18.             return KEYBOARD_7_AMPERSAND;
  19.         case 0x15:
  20.             return KEYBOARD_8_ASTERISK;
  21.         case 0x9:
  22.             return KEYBOARD_9_OPARENTHESIS;
  23.         case 0x16:
  24.             return KEYBOARD_BACKSPACE;
  25.         case 0x19:
  26.             return KEYBOARD_0_CPARENTHESIS;
  27.         case 0x0D:
  28.             return KEYBOARD_DELETE;
  29.         case 0x0C:
  30.             break;
  31.         case 0x18:
  32.             return KEYBOARD_UPARROW;
  33.         case 0x5E:
  34.             break;
  35.         case 0x08:
  36.             return KEYBOARD_LEFTARROW;
  37.         case 0x1C:
  38.             return KEYBOARD_ENTER;
  39.         case 0x5A:
  40.             return KEYBOARD_RIGHTARROW;
  41.         case 0x42:
  42.             break;
  43.         case 0x52:
  44.             return KEYBOARD_DOWNARROW;
  45.         case 0x4A:
  46.             break;
  47.         default:
  48.             break;
  49.     }
  50.     return 0;
  51. }
发送按键数据后还要发送一个空的包,表示按键抬起,不然会一直输入,在定时器哪里增加个变量来计时
  1. uint16_t release_key_time = 0;
  2. void IRTimeCount(uint32_t us)
  3. {
  4.     IR_time_us += us;
  5.     if(release_key_time > us)
  6.     {
  7.         release_key_time -= us;
  8.     }
  9.     else if(release_key_time > 0)
  10.     {
  11.         release_key_time = 1;
  12.     }
  13. }
  14. void IRAPP(void)
  15. {
  16.     uint8_t HID_Buffer[8] = {0};
  17.     if(ir_pin_it_flag != 0)
  18.     {
  19.         ir_pin_it_flag = 0;
  20.         IRIOcheck(!LL_GPIO_IsInputPinSet(IR_PIN_GPIO_Port,IR_PIN_Pin));
  21.     }
  22.     if(IR_code_flag == IR_CODE_FLAG_CMD)
  23.     {
  24.         //printf("rev ir data: %02X%02X%02X%02X\r\n",IR_code[0],IR_code[1],IR_code[2],IR_code[3]);
  25.         IR_code_flag = IR_CODE_FLAG_NONE;
  26.         if((IR_code[2]^IR_code[3]) == 0xFF)
  27.         {
  28.             HID_Buffer[2] = IRCode2Key(IR_code[2]);
  29.             USBD_HID_SendReport(&hUsbDeviceFS, HID_Buffer, 8);
  30.             release_key_time = 20000;
  31.         }
  32.     }
  33.     else if(IR_code_flag == IR_CODE_FLAG_REPEAT)
  34.     {
  35.         //printf("rev ir repeat\r\n");
  36.         IR_code_flag = IR_CODE_FLAG_NONE;
  37.     }
  38.     if(release_key_time == 1)
  39.     {
  40.         release_key_time = 0;
  41.         USBD_HID_SendReport(&hUsbDeviceFS, HID_Buffer, 8);
  42.     }
  43. }
需要注意开启USB后要注释掉串口相关操作,不然会有问题,我这里会出现发送空指令变成输入e的情况,最终效果如下

就实际使用来说蓝牙或者2.4G的遥控更好用,这个项目适合对红外解码和USB通讯的学习。



打赏榜单

21小跑堂 打赏了 60.00 元 2024-11-14
理由:恭喜通过原创审核!期待您更多的原创作品~~

评论

使用STM32F103+红外接收器模块实现遥控控制电脑,虽然实用性不强,但是用于学习红外解码和USB HID设备很是好用。  发表于 2024-11-14 15:44
AdaMaYun 发表于 2024-11-11 17:28 | 显示全部楼层
适合对红外解码和USB通讯的学习
海洋无限 发表于 2024-11-25 22:30 | 显示全部楼层

适合对红外解码
ldg999 发表于 2025-1-7 21:12 | 显示全部楼层
感谢分享,学习一下
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:同飞软件研发工程师
简介:制冷系统单片机软件开发,使用PID控制温度

161

主题

815

帖子

10

粉丝
快速回复 在线客服 返回列表 返回顶部