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

[MM32生态] 基于MM32与TFBS4711实现IrDA红外通讯

[复制链接]
 楼主| xld0932 发表于 2022-2-12 23:54 | 显示全部楼层 |阅读模式
<
本帖最后由 xld0932 于 2022-2-13 00:01 编辑

#申请原创#   @21小跑堂

IrDA百科
IrDAInfrared Data Association(红外线数据标准协会)的英文缩写,IrDA红外接口是一种红外线无线传输协议以及基于该协议的无线传输接口。它是用来取代点对点的线缆连接,具有小角度(30度锥角以内)、短距离、点对点直线数据传输、保密性强的特点。在IrDA物理层中,根据数据通讯速率将其分为这几类:SIR9.6kbps~115.2kbps)、MIR0.576Mbps1.152Mbps)、FIR4Mbps)和VFIR16Mbps)。

MM32F0140 & IrDA
官方在MM32F0140用户手册中,关于UART简介中有写到:对于使用工业标准NRZ异步串行数据格式的外设,通过异步收发器(UART)可以灵活的与之进行全双工数据交换;通过分数波特率发生器,UART还可以选择宽范围的波特率;还支持异步单向通讯和半双工通讯、调制解调器(CTS/RTS)操作、以及IrDA红外通讯功能。

MM32F0140系列芯片UART支持IrDA SIR ENDEC规范的红外功能;当UART工作在IrDA红外模式时(SIREN寄存器位使能),UARTSTOP位必须配置成1个停止位;UART TX引脚默认输出高电平。结合选用的IrDA收发器TFBS4711,以及SIR ENDEC应用,UART最低传输速率需达到9.6kbps,最高不得超过115.2kbps

SIR可以工作在正常模式,也可以工作在低功耗模式,可以通过SIRLP这个寄存器位来进行配置选择。IrDA SIR物理层规定使用反相归零调制方式(RZI),该方式用一个红外光脉冲代表逻辑0;在正常模式下,0的脉冲宽度为3/16位长度。在低功耗模式下,脉冲宽度将不再是3/16位长度,而是低功耗波特率时钟周期的3倍(SIRLP_CLK*3),低功耗模式下的频率SIRLP_CLK可以通过PSC预分频器,对UART时钟源PCLK进行分频来设置,该频率范围需要设定在1.42MHz < SIRLP_CLK < 2.12MHz之间。
21186207d6742cdbc.png

SIR发送编码器和SIR接收译码器实现了UART比特流与红外脉冲流之间的相互转换:SIR发送编码器把逻辑0作为高电脑发送,把逻辑1作为低电平发送;而SIR接收译码器则是将接收到的IrDA信号转变成比特数据后再发送给UART

IrDA红外通讯是一个半双工通讯协议,编解码不可以同时进行:如果发送器处于忙的状态,也就是UART TX正在传输数据给IrDA编码器,IrDA接收线上的任何数据都将被IrDA解码器忽略;如果接收器处于忙的状态下,也就是说UART RX正在接收来自于IrDA解码器的数据,UART TXIrDA的数据将不会被IrDA进行编码和传输;所以当收发数据时应当避免同时操作,以保证数据的正确性。

原理图设计
对于硬件的功能主要是测试IrDA红外通讯功能,所以功能相对简单;在原理图设计的时候,在MM32F0140最小系统的基础上增加了一个LED灯、一个KEY按键、一个CH340用于在程序调试过程中来输出运行日志等信息、最后就是一个TFB84711;对于MCU的下载接口我们使用JTAGSWD下载模式,具体的设计图纸如下所示:
376686207d6b9d5029.png

PCB设计
在原理图完成之后,先根据需求检查功能是否都满足了、再检查一下原理图设计,最后将其转换成PCB进行布线;在布线完成后,检查DRC没有问题后,生成GERBER文件进行投板。完成的PCB图纸如下所示:
526706207d6d1c06f4.png

回板焊接调试
因为IrDA红外通讯是点对点的,最小需要两块PCBA来配合,所以就手工焊接了两块PCB
100216207d6efc29f7.png

在开始调试之前除了焊接硬件,也需要基于原理图设计来准备测试程序,这个开发的测试工程就包括了LED闪烁、按键识别和处理、通过UART1CH340来与PC端的调试终端实现数据通讯的功能;在基础功能调试完成了,就开始来实现IrDA的底层配置、功能,并通过串口调试终端软件来实现两块板子上的IrDA红外数据的收发功能。

代码实现:LED
  1. /*******************************************************************************
  2. * [url=home.php?mod=space&uid=288409]@file[/url]    LED.c
  3. * [url=home.php?mod=space&uid=187600]@author[/url]  King
  4. * [url=home.php?mod=space&uid=895143]@version[/url] V1.00
  5. * [url=home.php?mod=space&uid=212281]@date[/url]    21-Dec-2021
  6. * [url=home.php?mod=space&uid=247401]@brief[/url]   ......
  7. *******************************************************************************/

  8. /* Define to prevent recursive inclusion -------------------------------------*/
  9. #define __LED_C__


  10. /* Includes ------------------------------------------------------------------*/
  11. #include "LED.h"


  12. /* Private typedef -----------------------------------------------------------*/
  13. /* Private define ------------------------------------------------------------*/
  14. /* Private macro -------------------------------------------------------------*/
  15. /* Private variables ---------------------------------------------------------*/
  16. /* Private function prototypes -----------------------------------------------*/
  17. /* Private functions ---------------------------------------------------------*/


  18. /* Exported variables --------------------------------------------------------*/
  19. /* Exported function prototypes ----------------------------------------------*/


  20. /*******************************************************************************
  21. * [url=home.php?mod=space&uid=247401]@brief[/url]      
  22. * @param      
  23. * @retval      
  24. * [url=home.php?mod=space&uid=93590]@Attention[/url]   
  25. *******************************************************************************/
  26. void LED_Init(void)
  27. {
  28.     GPIO_InitTypeDef GPIO_InitStructure;

  29.     RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);

  30.     GPIO_StructInit(&GPIO_InitStructure);
  31.     GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_1;
  32.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  33.     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
  34.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  35.     GPIO_WriteBit(GPIOA, GPIO_Pin_1, Bit_RESET);

  36.     TASK_Append(TASK_ID_LED,  LED_Toggle,  250);
  37. }


  38. /*******************************************************************************
  39. * [url=home.php?mod=space&uid=247401]@brief[/url]      
  40. * @param      
  41. * @retval      
  42. * [url=home.php?mod=space&uid=93590]@Attention[/url]   
  43. *******************************************************************************/
  44. void LED_Toggle(void)
  45. {
  46.     if(!GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_1))
  47.     {
  48.         GPIO_WriteBit(GPIOA, GPIO_Pin_1, Bit_SET);
  49.     }
  50.     else
  51.     {
  52.         GPIO_WriteBit(GPIOA, GPIO_Pin_1, Bit_RESET);
  53.     }
  54. }


  55. /******************* (C) COPYRIGHT 2021 *************************END OF FILE***/


代码实现:KEY按键
  1. /*******************************************************************************
  2. * [url=home.php?mod=space&uid=288409]@file[/url]    KEY.c
  3. * [url=home.php?mod=space&uid=187600]@author[/url]  King
  4. * [url=home.php?mod=space&uid=895143]@version[/url] V1.00
  5. * [url=home.php?mod=space&uid=212281]@date[/url]    21-Dec-2021
  6. * @brief   ......
  7. *******************************************************************************/

  8. /* Define to prevent recursive inclusion -------------------------------------*/
  9. #define __KEY_C__


  10. /* Includes ------------------------------------------------------------------*/
  11. #include "KEY.h"


  12. /* Private typedef -----------------------------------------------------------*/
  13. /* Private define ------------------------------------------------------------*/
  14. /* Private macro -------------------------------------------------------------*/
  15. /* Private variables ---------------------------------------------------------*/
  16. /* Private function prototypes -----------------------------------------------*/
  17. /* Private functions ---------------------------------------------------------*/


  18. /* Exported variables --------------------------------------------------------*/
  19. /* Exported function prototypes ----------------------------------------------*/


  20. /*******************************************************************************
  21. * @brief      
  22. * @param      
  23. * @retval      
  24. * [url=home.php?mod=space&uid=93590]@Attention[/url]   
  25. *******************************************************************************/
  26. void KEY_Init(void)
  27. {
  28.     GPIO_InitTypeDef GPIO_InitStructure;

  29.     RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);

  30.     GPIO_StructInit(&GPIO_InitStructure);
  31.     GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0;
  32.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
  33.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  34.     TASK_Append(TASK_ID_KEY, KEY_Scan, 10);
  35. }


  36. /*******************************************************************************
  37. * @brief      
  38. * @param      
  39. * @retval      
  40. * @attention   
  41. *******************************************************************************/
  42. void KEY_SubScan(uint8_t *State, uint8_t *Count, uint8_t Value, char *Name)
  43. {
  44.     if(*State == 0)
  45.     {
  46.         if(Value != Bit_RESET) *Count += 1;
  47.         else                   *Count  = 0;

  48.         if(*Count > 5)
  49.         {
  50.             *Count = 0; *State = 1;
  51.             printf("\r\n%s Pressed", Name);
  52.         }
  53.     }
  54.     else
  55.     {
  56.         if(Value == Bit_RESET) *Count += 1;
  57.         else                   *Count  = 0;

  58.         if(*Count > 5)
  59.         {
  60.             *Count = 0; *State = 0;
  61.             printf("\r\n%s Release", Name);
  62.         }
  63.     }
  64. }


  65. /*******************************************************************************
  66. * @brief      
  67. * @param      
  68. * @retval      
  69. * @attention   
  70. *******************************************************************************/
  71. void KEY_Scan(void)
  72. {
  73.     static uint8_t KeyState = 0;
  74.     static uint8_t KeyCount = 0;

  75.     KEY_SubScan(&KeyState, &KeyCount, GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0), "KEY");
  76. }


  77. /******************* (C) COPYRIGHT 2021 *************************END OF FILE***/


代码实现:UART2 & SHELL接口移植
  1. /*******************************************************************************
  2. * [url=home.php?mod=space&uid=288409]@file[/url]    shell_port.c
  3. * [url=home.php?mod=space&uid=187600]@author[/url]  King
  4. * [url=home.php?mod=space&uid=895143]@version[/url] V1.00
  5. * [url=home.php?mod=space&uid=212281]@date[/url]    21-Dec-2021
  6. * @brief   ......
  7. *******************************************************************************/

  8. /* Define to prevent recursive inclusion -------------------------------------*/
  9. #define __SHELL_PORT_C__


  10. /* Includes ------------------------------------------------------------------*/
  11. #include "shell_port.h"


  12. /* Private typedef -----------------------------------------------------------*/
  13. /* Private define ------------------------------------------------------------*/
  14. /* Private macro -------------------------------------------------------------*/


  15. /* Private variables ---------------------------------------------------------*/
  16. SHELL_TypeDef shell;


  17. /* Private function prototypes -----------------------------------------------*/
  18. /* Private functions ---------------------------------------------------------*/


  19. /* Exported variables --------------------------------------------------------*/
  20. /* Exported function prototypes ----------------------------------------------*/


  21. /*******************************************************************************
  22. * @brief      
  23. * @param      
  24. * @retval      
  25. * @attention   
  26. *******************************************************************************/
  27. void shellPortWrite(const char ch)
  28. {
  29.     UART_SendData(UART2, (uint8_t)ch);
  30.     while(UART_GetFlagStatus(UART2, UART_IT_TXIEN) == RESET);
  31. }


  32. /*******************************************************************************
  33. * @brief      
  34. * @param      
  35. * @retval      
  36. * @attention   
  37. *******************************************************************************/
  38. void shellPortInit(void)
  39. {
  40.     GPIO_InitTypeDef GPIO_InitStructure;
  41.     NVIC_InitTypeDef NVIC_InitStructure;
  42.     UART_InitTypeDef UART_InitStructure;

  43.     RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA,   ENABLE);
  44.     RCC_APB1PeriphClockCmd(RCC_APB1ENR_UART2, ENABLE);

  45.     NVIC_InitStructure.NVIC_IRQChannel = UART2_IRQn;
  46.     NVIC_InitStructure.NVIC_IRQChannelPriority = 1;
  47.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  48.     NVIC_Init(&NVIC_InitStructure);

  49.     UART_StructInit(&UART_InitStructure);
  50.     UART_InitStructure.UART_BaudRate            = 115200;
  51.     UART_InitStructure.UART_WordLength          = UART_WordLength_8b;
  52.     UART_InitStructure.UART_StopBits            = UART_StopBits_1;
  53.     UART_InitStructure.UART_Parity              = UART_Parity_No;
  54.     UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None;
  55.     UART_InitStructure.UART_Mode                = UART_Mode_Rx | UART_Mode_Tx;
  56.     UART_Init(UART2, &UART_InitStructure);

  57.     UART_ITConfig(UART2, UART_IT_RXIEN, ENABLE);

  58.     UART_Cmd(UART2, ENABLE);

  59.     GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_1);
  60.     GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_1);

  61.     GPIO_StructInit(&GPIO_InitStructure);
  62.     GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_2;
  63.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  64.     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
  65.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  66.     GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_3;
  67.     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN_FLOATING;
  68.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  69.     shell.write = shellPortWrite;
  70.     shellInit(&shell);
  71. }


  72. /*******************************************************************************
  73. * @brief      
  74. * @param      
  75. * @retval      
  76. * @attention   
  77. *******************************************************************************/
  78. void UART2_IRQHandler(void)
  79. {
  80.     if(UART_GetITStatus(UART2, UART_IT_RXIEN) != RESET)
  81.     {
  82.         shellHandler(&shell, UART_ReceiveData(UART2));
  83.         UART_ClearITPendingBit(UART2,  UART_IT_RXIEN);
  84.     }
  85. }


  86. /*******************************************************************************
  87. * @brief      
  88. * @param      
  89. * @retval      
  90. * @attention   
  91. *******************************************************************************/
  92. int fputc(int ch, FILE *f)
  93. {
  94.     UART_SendData(UART2, (uint8_t)ch);
  95.     while(UART_GetFlagStatus(UART2, UART_IT_TXIEN) == RESET);

  96.     return ch;
  97. }


  98. /******************* (C) COPYRIGHT 2021 *************************END OF FILE***/


代码实现:UART1 & IrDA实现
  1. /*******************************************************************************
  2. * @file    IrDA.c
  3. * @author  King
  4. * @version V1.00
  5. * @date    21-Dec-2021
  6. * @brief   ......
  7. *******************************************************************************/

  8. /* Define to prevent recursive inclusion -------------------------------------*/
  9. #define __IrDA_C__


  10. /* Includes ------------------------------------------------------------------*/
  11. #include "IrDA.h"


  12. /* Private typedef -----------------------------------------------------------*/
  13. /* Private define ------------------------------------------------------------*/
  14. /* Private macro -------------------------------------------------------------*/
  15. /* Private variables ---------------------------------------------------------*/
  16. /* Private function prototypes -----------------------------------------------*/
  17. /* Private functions ---------------------------------------------------------*/


  18. /* Exported variables --------------------------------------------------------*/
  19. /* Exported function prototypes ----------------------------------------------*/


  20. /*******************************************************************************
  21. * @brief      
  22. * @param      
  23. * @retval      
  24. * @attention   
  25. *******************************************************************************/
  26. void IrDA_Init(void)
  27. {
  28.     GPIO_InitTypeDef GPIO_InitStructure;
  29.     NVIC_InitTypeDef NVIC_InitStructure;
  30.     UART_InitTypeDef UART_InitStructure;

  31.     RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA,   ENABLE);
  32.     RCC_APB2PeriphClockCmd(RCC_APB2ENR_UART1, ENABLE);

  33.     NVIC_InitStructure.NVIC_IRQChannel = UART1_IRQn;
  34.     NVIC_InitStructure.NVIC_IRQChannelPriority = 1;
  35.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  36.     NVIC_Init(&NVIC_InitStructure);

  37.     UART_StructInit(&UART_InitStructure);
  38.     UART_InitStructure.UART_BaudRate            = 115200;
  39.     UART_InitStructure.UART_WordLength          = UART_WordLength_8b;
  40.     UART_InitStructure.UART_StopBits            = UART_StopBits_1;
  41.     UART_InitStructure.UART_Parity              = UART_Parity_No;
  42.     UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None;
  43.     UART_InitStructure.UART_Mode                = UART_Mode_Rx | UART_Mode_Tx;
  44.     UART_Init(UART1, &UART_InitStructure);

  45.     UART_ClearITPendingBit(UART1, UART_IT_RXIEN);

  46.     UART_ITConfig(UART1, UART_IT_RXIEN, ENABLE);

  47.     UART_Cmd(UART1, ENABLE);

  48.     GPIO_PinAFConfig(GPIOA, GPIO_PinSource9,  GPIO_AF_1);
  49.     GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1);

  50.     GPIO_StructInit(&GPIO_InitStructure);
  51.     GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_9;
  52.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  53.     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
  54.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  55.     GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_10;
  56.     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN_FLOATING;
  57.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  58.     GPIO_StructInit(&GPIO_InitStructure);
  59.     GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_11;
  60.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  61.     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
  62.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  63.     GPIO_WriteBit(GPIOA, GPIO_Pin_11, Bit_RESET);

  64.     /* SIRLPP_CLK = PCLK2 / 0x28 = 72000000 / 40 = 1.8MHz */
  65.     UART1->IRDA = 0x00002801;
  66. }


  67. /*******************************************************************************
  68. * @brief      
  69. * @param      
  70. * @retval      
  71. * @attention   
  72. *******************************************************************************/
  73. void UART1_IRQHandler(void)
  74. {
  75.     if(UART_GetITStatus(UART1, UART_IT_RXIEN) != RESET)
  76.     {
  77.         QUEUE_WRITE(QUEUE_IrDA_RX_IDX, UART_ReceiveData(UART1));
  78.         UART_ClearITPendingBit(UART1,  UART_IT_RXIEN);
  79.     }
  80. }


  81. /*******************************************************************************
  82. * @brief      
  83. * @param      
  84. * @retval      
  85. * @attention   
  86. *******************************************************************************/
  87. void IrDA_SendData(uint8_t Data)
  88. {
  89.     UART_SendData(UART1, Data);
  90.     while(UART_GetFlagStatus(UART1, UART_IT_TXIEN) == RESET);
  91. }


  92. /*******************************************************************************
  93. * @brief      
  94. * @param      
  95. * @retval      
  96. * @attention   
  97. *******************************************************************************/
  98. void IrDA_SHELL_Handler(uint8_t Data)
  99. {
  100.     printf("\r\nIrDA TX : ");

  101.     for(uint8_t i = 0; i < 10; i++)
  102.     {
  103.         IrDA_SendData(Data+i);

  104.         printf("0x%02x ", Data+i);
  105.     }
  106. }
  107. SHELL_EXPORT_CMD(IrDA, IrDA_SHELL_Handler, IrDA Send Data);


  108. /******************* (C) COPYRIGHT 2021 *************************END OF FILE***/


测试运行结果
两块硬件单板,通过SHELL命令的调用方式,错开时间相互发送数据:
78246207d7f28a7cf.png

后续
MM32F0140系列MCUIrDA红外通讯功能,它遵循的是IrDA SIR ENDEC规范;而NEC编码是红外遥控器编码方式的一种,它是一个满足特定时序和频率的载波通讯协议,它们唯一的共性就是使用红外进行通讯,所以刚到很多网友在问如何通过MCUIrDA来实现对于遥控器的解码,这个这么说吧,我现在还没想到怎么来实现。

软件工程源代码
Template.zip (716 KB, 下载次数: 58)



打赏榜单

21小跑堂 打赏了 100.00 元 2022-02-17
理由:恭喜通过原创奖审核!请多多加油哦!

评论

lihai  发表于 2022-2-24 12:17
内政奇才 发表于 2022-2-14 16:51 来自手机 | 显示全部楼层
提供的资料很全
 楼主| xld0932 发表于 2022-2-14 17:39 | 显示全部楼层

多谢支持
chenjun89 发表于 2022-2-14 18:26 来自手机 | 显示全部楼层
谢谢楼主分享,参考一下。
海滨消消 发表于 2022-2-16 10:20 来自手机 | 显示全部楼层
感谢楼主分享
laocuo1142 发表于 2022-2-25 09:41 | 显示全部楼层
本帖赏金 100.00元
LED2013 发表于 2022-2-28 22:26 | 显示全部楼层
厉害,PCB画的真规整
drer 发表于 2022-3-1 11:59 | 显示全部楼层
一般来说通讯距离是多少
qcliu 发表于 2022-3-1 12:11 | 显示全部楼层
这种非常见功底啊
coshi 发表于 2022-3-1 12:15 | 显示全部楼层
长期不发送数据会断开连接吗
kxsi 发表于 2022-3-1 12:56 | 显示全部楼层
发送时候功耗是多少啊
wiba 发表于 2022-3-1 13:44 | 显示全部楼层
最快的传输速度是多少呢
 楼主| xld0932 发表于 2022-3-1 17:03 | 显示全部楼层
wiba 发表于 2022-3-1 13:44
最快的传输速度是多少呢

这个是由红外收发头TFBS4711这个器件决定的
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:King.Xu

77

主题

3023

帖子

38

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