用IO口模拟串口(外部中断+定时器)--附程序附测试结果

2023-05-16

       给大家分享一下我用IO口模拟串口的一种方法,经测试使用这种方法发送能支持115200波特率,接收9600波特率测试没问题,接收波特率能否提高受制于用户应用场景是否能允许微妙级别的频繁中断了,我实际使用由于MCU主频不高(才32M),处理能力有点差,9600波特率勉强能接受。如果你的MCU主频很高而且使用到的中断也不多,是可以将接受波特率往上提升的。

      下面介绍一下我模拟串口使用的方法,我采用的是外部中断+定时器的组合来实现的,将接收引脚(RXD)配置为外部中断引脚,下降沿触发,配置为外部中断主要作用是用来检测是否有数据发送过来,当有数据过来时,首先接收的是起始位,此时产生中断,然后在中断中使能定时器,这时再失能外部中断,此时外部中断不再参与接收,数据流接收全部交给定时器来处理。定时器分频设置为1Mhz,重载值初始设置为波特率对应时间的一半(例如9600波特率,一比特需要104us,那么定时器重装载值设置为52us),定时器开始工作后,触发第一个更新中断(52us),此时读取RXD引脚电平,判断是否是起始位,起始位判断完成后立马将定时器的重装载值更改为104us,然后每隔104us对RXD引脚电平进行采样,采样8次,然后检测停止位是否到来,停止位检测完成后,表示一个字节数据接收完成,此时进行空闲检测,检测方法是连续3次采样都是高电平,说明信号线处在空闲状态了,此时可以认为一帧数据接收完毕,可以置位标志位通知主程序进行数据处理了。但是实际测试发现数据长了之后会出现乱码情况,用逻辑分析仪分析发现测试采样点和理论采样点偏离太多了,产生这种现象的原因主要是定时器定时不准有关,为了解决这个问题,就得每隔几个字节用外部中断来做同步,把采样点偏移修正到正常位置,加了同步之后数据长也不会出现乱码情况。

采样这种方法的优点有如下几点:

1.不用在中断服务函数里面进行延时

2.接收逻辑清晰,易移植,易使用

3.接收数据处理可以和硬件串口接收程序兼容

4.具备空闲检测(类似STM32 IDLE中断)

5.可以用于低功耗模式串口唤醒

缺点如下:

1.波特率无法设置太高

2.波特率高时中断过于频繁

3.需要使用两个定时器实现收发

4.空闲标志无法通过中断告知用户,用户需要不断轮询接收完成标志

串口帧结构如下:

115200数据发送测试波形如下:

 从上面的结果看只要微妙延时准确就能正确解析出数据

9600接收波形如下:

 从波形看MCU的采样时刻位于比特位的中间时刻,此时RXD上数据已经保持平稳了,此时采样比较合适。一帧数据的最后三个边沿就是空闲检测用的,连续三个比特间隔没有检测到起始位即认为一帧数据结束了。

使用模拟串口自发自收测试结果如下(9600波特率):

 从上面测试结果看没有出现丢包现象,仔细查看也没有发现乱码数据出现,测试结果比较满意。

使用模拟串口自发自收测试结果如下(38400波特率):

 从上面结果看38400波特率下也没有出现丢包,也没发现乱码情况。

使用模拟串口自发自收测试结果如下(115200波特率):

 在115200波特率下,就会出现乱码了,如果MCU改成F407应该问题也不大,只是中断确实比较频繁,不知有没有什么办法能够解决,我个人觉得解决的办法就是高波特率使用场合避免使用模拟串口转而使用硬件串口,模拟串口仅仅用来应急或者通信速率不高的场合。

参考代码如下(基于STM32L151芯片编写与测试,使用的是LL库):

/* 模拟串口用到的结构体 */
typedef struct
{
  uint32_t baud_t;    /* 波特率(时间表示) */
  uint32_t samp_t;    /* 采样时间 */
  uint8_t process;    /* 接收处理流程 */
  uint8_t buff[256];  /* 接收缓存 */
  uint8_t len;        /* 接收长度 */
  uint8_t flag;       /* 接收空闲标志 */
}suart_t;


/**
  * 说明 : 微妙定时器(用于模拟串口接收)
  * 参数 : 无
  * 返回 : 无
  */
void Suart_Timer_Init(void)
{
    uint32_t st=Suart.baud_t*0.5f-1;
    LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM6);	
	/** 定时器时基配置 */
	LL_TIM_SetPrescaler(TIM6, 31);

	LL_TIM_SetAutoReload(TIM6, Suart.samp_t-1);	
	LL_TIM_SetCounterMode(TIM6, LL_TIM_COUNTERMODE_UP);
    LL_TIM_SetClockSource(TIM6, LL_TIM_CLOCKSOURCE_INTERNAL);
	LL_TIM_GenerateEvent_UPDATE(TIM6);
	LL_TIM_ClearFlag_UPDATE(TIM6);	
	/** 配置中断 */
    LL_TIM_EnableIT_UPDATE(TIM6);
	
    NVIC_EnableIRQ(TIM6_IRQn); 
	NVIC_SetPriority(TIM6_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 2, 0));	
 
}

/**
  * 说明 : 微妙延时定时器初始化(用于模拟串口数据发送)
  * 参数 : 无
  * 返回 : 无
  */
void Delay_Timer_Init(void)
{
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM7);	
	LL_TIM_SetPrescaler(TIM7, 3);
	LL_TIM_SetAutoReload(TIM7, 7);	
	LL_TIM_SetCounterMode(TIM7, LL_TIM_COUNTERMODE_UP);
  LL_TIM_EnableARRPreload(TIM7);
  LL_TIM_SetClockSource(TIM7, LL_TIM_CLOCKSOURCE_INTERNAL);
	LL_TIM_GenerateEvent_UPDATE(TIM7);
	LL_TIM_ClearFlag_UPDATE(TIM7);
  LL_TIM_EnableCounter(TIM7); 

}

/**
  * 说明 : 软件模拟串口初始化
  * 参数 : buad, 波特率(最大9600)
  * 返回 : 无
  */
void Soft_Uart_Init(uint32_t baud)
{
	LL_GPIO_InitTypeDef  GPIO_InitStruct={0};  
	LL_EXTI_InitTypeDef EXTI_InitStruct={0};
  
    LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);

    /* 置位 */
    LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_12);  
  
    /* UART_RX-> PA12, UART_TX->PA11 */
    GPIO_InitStruct.Pin = LL_GPIO_PIN_11;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);  
  
    GPIO_InitStruct.Pin = LL_GPIO_PIN_12;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_INPUT;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct); 
  
	LL_SYSCFG_SetEXTISource(LL_SYSCFG_EXTI_PORTA, LL_SYSCFG_EXTI_LINE12);
	EXTI_InitStruct.Line_0_31 = LL_EXTI_LINE_12;
	EXTI_InitStruct.Mode = LL_EXTI_MODE_IT;
	EXTI_InitStruct.Trigger = LL_EXTI_TRIGGER_FALLING;
	EXTI_InitStruct.LineCommand = ENABLE;
	LL_EXTI_Init(&EXTI_InitStruct);
  
    NVIC_EnableIRQ(EXTI15_10_IRQn); 
	NVIC_SetPriority(EXTI15_10_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 1, 0));
  /* 根据波特率设置每个比特延时时间 */
  Suart.baud_t = 1000000/baud;
  Suart.samp_t = Suart.baud_t * 0.5f;
  /* 这个定时器用于接收 */
  Suart_Timer_Init();
  /* 这个定时器用于发送 */
  Delay_Timer_Init();
}

/* GPIO引脚宏定义 */
#define TXD_H()        LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_11)
#define TXD_L()        LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_11)
#define READ_RX()      LL_GPIO_IsInputPinSet(GPIOA, LL_GPIO_PIN_12)

/**
  * 说明 : 软件模拟串口1字节数据发送(经测试发送速率最大支持115200)
  * 参数 : data, 数据
  * 返回 : 无
  */
void Suart_Tx_Byte(uint8_t data)
{
  /* 起始位 */
  TXD_L();
  Delay_Us(Suart.baud_t);
  for(uint8_t i=0; i<8; i++)
  {
    if(data & 0x01)
    {
      TXD_H();
    }
    else
    {
      TXD_L();
    }
    data >>= 1;
    Delay_Us(Suart.baud_t);
  }
  /* 停止位 */
  TXD_H();
  Delay_Us(Suart.baud_t);
}

/**
  * 说明 : 软件模拟串口n字节数据发送
  * 参数 : ptr, 数据指针
  *        len, 发送字节数
  * 返回 : 无
  */
void Suart_Tx_Nbyte(uint8_t* ptr, uint16_t len)
{
  while(len--)
  {
    Suart_Tx_Byte(*ptr);
    ptr++;
  }
}



/**
  * 说明 : 定时器2中断服务函数(串口数据接收)
  * 参数 : 无
  * 返回 : 无
  */ 
#if 1
void TIM6_IRQHandler(void)
{
  uint8_t bit=1;
  static uint8_t byte;
  static uint8_t num;
  static uint8_t idle;
  static uint8_t sync_count;
  if(LL_TIM_IsActiveFlag_UPDATE(TIM6) != RESET)
  {
    LL_TIM_ClearFlag_UPDATE(TIM6);
    bit = READ_RX();
    switch(Suart.process)
    {
      case 0:
        /* 起始位检测 */
        if(bit == 0)
        {
          num = 0x01;
          byte = 0;
          idle = 0;
          LL_TIM_SetCounter(TIM6, 0);
          LL_TIM_SetAutoReload(TIM6, Suart.baud_t-1);
          Suart.process = 1;
        }
        else
        {
          /* 串口空闲检测 */
          idle++;
          if(idle > 3)
          {
            idle = 0;
            LL_TIM_SetCounter(TIM6, 0);
            LL_TIM_SetAutoReload(TIM6, Suart.samp_t-1);            
            LL_TIM_DisableCounter(TIM6);
            LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_12);
            NVIC_EnableIRQ(EXTI15_10_IRQn);  

            /* 串口空闲了,表示一帧数据接收完成了(这里类似STM32 IDLE中断) */            
            Suart.flag = 1;
          }
        }
        break;
      case 1:
        /* 接收一字节数据 */
        if(bit == 1)
        {
          byte |= num;
        }
        num = num << 1;        
        if(num == 0)
        {
          Suart.process = 0x02;
        }
        break;
      case 2:
        /* 停止位检测 */
        if(bit == 1)
        {
          /* 运行到这表示一个字节接收完成了 */
          Suart.buff[Suart.len++] = byte; 
          sync_count++; 
          /* 每隔几个字节同步一下 */
          if(sync_count == 5)
          {
            sync_count=0;
            LL_TIM_SetCounter(TIM6, 0);
            LL_TIM_SetAutoReload(TIM6, Suart.samp_t-1);            
            LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_12);
            NVIC_EnableIRQ(EXTI15_10_IRQn); 
          }        
          Suart.process = 0x00;
        }
        break;
    }
  }
}
#endif

/**
  * 说明 : 外部中断9-5的中断服务函数
  * 参数 : 无
  * 返回 : 无
  */ 
void EXTI15_10_IRQHandler(void)
{
  if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_12) != RESET)
  {
    LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_12);
    NVIC_DisableIRQ(EXTI15_10_IRQn);
    Suart.process = 0;
    /* 打开定时器,开始解析比特流 */
    LL_TIM_SetCounter(TIM6, 0);
    LL_TIM_EnableCounter(TIM6);
  }
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

用IO口模拟串口(外部中断+定时器)--附程序附测试结果 的相关文章

  • android studio配置lambda教程

    java1 8的特性之一便是随同发布的lambda表达式 xff0c 它将允许我们将行为传到函数里 在Java 8之前 xff0c 如果想将行为传入函数 xff0c 仅有的选择就是匿名类 xff0c 需要6行代码 而定义行为最重要的那行代码
  • Gtsam学习笔记

    Gtsam学习笔记 文章目录 Gtsam学习笔记 cmake引入 因子factor 预定义的factor 生成factor 初值定义 噪声定义 优化方法 GaussNewton法 LevenbergMarquardt法 边缘化 margin
  • (ADRC)自抗扰控制器学习总结(一)

    ADRC自抗扰控制基本思想要点 xff1a 1 标准型与总扰动 xff0c 扩张状态与扰动整体辨识 xff0c 微分信号生成与安排过渡过程以及扰动的消减与控制量产生 ADRC主要构成 xff1a 1 gt 跟踪微分器 xff08 TD xf
  • 四旋翼姿态解算原理

    姿态结算原理 旋转矩阵的建立 如果要进行四旋翼姿态分析 xff0c 那么需要进行坐标系与坐标系之间的转换 xff0c 地理坐标系与四旋翼坐标系之间的联系如图2 6所示 四旋翼 Quad rotor 分别绕三个轴转动的角度变化如图2 7 所示
  • 四旋翼无人机的设计与实现讲解

    四旋翼无人机基于stm32的设计与实现过程
  • (ADRC)自抗扰控制器(二)——四旋翼无人机

    自抗扰四旋翼控制中的几个问题 xff1a 自抗扰控制器包含三大部分 xff1a TD微分跟踪器 xff1a 微风跟踪器主要可以安排过渡 xff0c 过程同时还具有一定的滤波功能 xff0c 四旋翼由遥控器和地面站发送期望控制信号 xff0c
  • ROS下实现darknet_ros目标检测

    一 代码下载 代码Github主页 xff1a https github com leggedrobotics darknet ros 打开命令行终端 xff0c 键入以下命令下载 span class token function mkd
  • Nginx $request_uri和$uri详解

    一 官方介绍 request uri This variable is equal to the original request URI as received from the client including the args It
  • C++学习总结(二十七)——STL容器与算法(一) STL容器的组成,线性容器(array,vector,tuple,queue,deque,stack),链式容器(list)

    STL容器 xff1a C 43 43 标准库的一部分 xff0c 用C 43 43 Template机制表达泛型的库 xff0c 用泛型技术设计完成实例 Template特性 1 类模板偏特化 xff0c 进行严格的类型检查 2 默认模板
  • C++学习总结(二十八)——STL容器与算法(二) 集合set multiset bitset 映射 map 以及散列hash的介绍

    1 集合set的基本操作 集合中不能包含重复的元素 xff0c 如果包含重复的元素 xff0c 则将被自动剔除 同时实现自动排序 红黑树容器 xff1a 例如数据 xff1a 1 2 3 4 5 6 7 经过排序后的结果为 xff1a 4
  • Linux Ubuntu基本操作指令

    Linux的登录方式 xff1a 1 本地登录 2 远程登录 xff1a putty使用 查看运行级别 xff1a Linux运行级别0 6级 xff0c 0 关机 6 重启 1 单用户 2 3 多用户 可以通过runlevel 查看运行级
  • 微信小程序开发(一)

    微信小程序开发 目录 微信小程序开发 一 微信小程序开发 二 五 让小程序连接树莓派 六 xff1a 小程序控制面板设计 七 xff1a 树莓派如何解析小程序的信息 八 xff1a 树莓派如何回信息给小程序 九 xff1a 树莓派与微信小程
  • ssh远程失败,提示“REMOTE HOST IDENTIFICATION HAS CHANGED! ”解决办法

    搞了个谷歌云 xff0c 但是因为一些原因一直提示我在挖矿 xff0c 一脸懵逼 xff0c 估计是别人的脚本做了手脚 删了新建一个实例 xff0c 外部IP还是原来的 xff0c 使用ssh远程连接的时候发现提示 REMOTE HOST
  • 【滤波器学习笔记】一阶RC低通滤波

    一阶RC低通滤波 从模拟到数字 本文整理自网络 匠人手记 等书籍文章 模拟电路低通滤波时域 频域软件低通滤波 典型电路 图1 典型RC电路 直流 交流 脉冲信号都可以用它 时域 电容电流 xff1a I c 61 d q d t 61 d
  • 嵌入式:一种裸机编程多任务切换方法

    嵌入式 xff1a 一种裸机编程多任务切换方法 有时候为了实现一些简单的 对实时性要求不高的任务 xff0c 采用操作系统不仅增加了程序的复杂性 xff0c 对低性能单片机的资源占用也是值得考虑的问题 这时候操作系统可能不是必要的 xff0
  • 自动化学科领域高质量科技期刊T1级期刊

    自动化学科领域高质量科技期刊T1级期刊 控制理论与控制工程方向 序号 期刊名称 T1 01 IEEE Transactions on Automatic Control T1 02 Automatica T1 03 SIAM Journal
  • UR机器人手眼标定

    一 UR机器人位姿表示 默认情况下UR机器人的基坐标系和TCP如下图所示 xff1a 注意这里的TCP位置和坐标系都是在默认TCP配置的情况下 xff0c 默认的TCP配置如下图所示 xff1a 如果用户想要自己设置TCP的位置和坐标系就可
  • 《自抗扰控制技术》——第一遍阅读

    目录 感想摘抄自认为有用的结论第一章 xff1a 剖析经典PID调节器第二章 xff1a 跟踪微分器第三章 xff1a 非光滑反馈的功能和效率第四章 xff1a 扩张状态观测器第五章 xff1a 自抗扰控制器第六章 xff1a 自抗扰控制器
  • ROS Melodic版本下Gazebo的更新与安装

    ROS Melodic自带的Gazebo版本过低 xff0c 建议升级 span class token comment 1 首先 xff0c 查看Gazebo版本 出现的是 gazebo9 及其相关插件 span dpkg l span
  • 《自抗扰控制技术》——第二遍(仿真)

    目录 感想复现书上的仿真图像第一章 xff1a 剖析经典PID调节器第二章 xff1a 跟踪微分器第三章 xff1a 非光滑反馈的功能和效率第四章 xff1a 扩张状态观测器第五章 xff1a 自抗扰控制器第六章 xff1a 自抗扰控制器的

随机推荐

  • 使用MYNT-EYE-D相机跑开源代码VINS_Fusion

    使用MYNT EYE D相机跑开源代码VINS Fusion 这两天刚买了一个小觅智能公司型号为D1000 IR 120 Color的深度相机 xff0c 探索了一下在VINS Fusions上的融合方法 xff0c 折腾了很久才成功 xf
  • 修改docker默认存储路径

    默认情况下 xff0c docker镜像的默认存储路径是 var lib docker xff0c 这相当于直接挂载系统目录下 xff0c 而一般在搭系统时 xff0c 这个区都不会太大 xff0c 所以如果长期使用docker开发应用 x
  • 制作自己的rgb-d数据集

    今天自己用机器人采了一波数据 尝试着用自己采集的RGB D数据来跑slam2的RGB D例程 下面来记录一下 该文章主要是参考这篇博客 xff1a https blog csdn net qq 16481211 article detail
  • ROS中的一些基本概念

    主节点 xff08 master xff09 xff1a 负责节点到节点的消息与通信 用roscore命令来运行主节点 节点只有在需要注册自己信息或向其他节点发送请求时才能访问主节点 节点 xff08 node xff09 xff1a 是指
  • ros实践(一):编写一个自己的功能包

    创建ROS功能包的命令如下 xff1a catkin create pkg 功能包名称 依赖功能包1 依赖功能包2 实践 cd catkin ws src catkin create pkg my first ros pkg std msg
  • 多传感器融合技术(一)

    传感器融合 xff0c 一般可以分为四种 xff1a Early fusion Fusing the raw data xff0c 一般称为前融合 xff08 或数据融合 xff09 xff0c 汇总所有传感器的数据 xff0c 得到一个s
  • 多传感器融合技术(序)

    一 xff0e 概述 多传感器融合 xff08 Multi sensor Fusion MSF xff09 是利用计算机技术 xff0c 将来自多传感器或多源的信息和数据以一定的准则进行自动分析和综合 xff0c 以完成所需的决策和估计而进
  • 如何使用手机端、ipad端来编写博客

    今天收到一位粉丝的提问 xff0c 为此我特意去试了一下 xff0c 相信大家都知道CSDN的移动APP是不能写博客的 xff0c 那么我就想到用网页去试试 xff0c 但是当我搜索CSDN网页进去以后 xff0c 如图 xff1a 解法是
  • 上位机串口数据检验方式(二)——奇偶校验

    奇偶校验这个概念在逻辑设计里面经常会用到 xff0c 但有的人对奇偶校验的理解很混乱 奇偶校验是对数据传输正确性的一种校验方法 在数据传输前附加一位奇校验位 xff0c 用来表示传输的数据中 34 1 34 的个数是奇数还是偶数 xff0c
  • coco2017 数据集获取

    span class token comment 下载命令 span span class token function wget span http images cocodataset org zips train2017 zip sp
  • c++/opencv利用相机位姿估计实现2D图像像素坐标到3D世界坐标的转换

    最近在做自动泊车项目中的车位线检测 xff0c 用到了将图像像素坐标转换为真实世界坐标的过程 xff0c 该过程可以通过世界坐标到图像像素坐标之间的关系进行求解 xff0c 在我的一篇博文中已经详细讲解了它们之间的数学关系 xff0c 不清
  • C语言回调函数的定义和写法

    C语言中的回调函数 xff08 Callback Function xff09 1 定义和使用场合 回调函数是指 使用者自己定义一个函数 xff0c 实现这个函数的程序内容 xff0c 然后把这个函数 xff08 入口地址 xff09 作为
  • MATLAB到底有多厉害

    前言 有人说 xff0c MATLAB除了不会生孩子 xff0c 什么都会 矩阵运算 数据可视化 GUI xff08 用户界面 xff09 设计 甚至是连接其他编程语言 xff0c MATLAB都能轻松实现 xff01 那么 xff0c M
  • 无人机的偏航角,滚动角,俯仰角解释

    1 偏航角 xff08 yaw xff09 简单的定义 xff1a 就是实际航向与计划航向之间的夹角 xff0c 如图所示 深刻的定义 xff1a 机轴 xff08 沿机头方向 xff09 水平投影与地轴的夹角 xff0c 如图所示 或者
  • STM32H743,基于LL库实现adc采样(ADC+DMA+TIM)

    买了一块正点原子的阿波罗H743开发板 xff0c 最近在调试ADC采样 xff0c 由于CubeMx生成的是HAL库格式的代码 xff0c HAL库使用时太占用资源了不喜欢 xff0c 个人比较喜欢LL库 xff0c 这个库和STD库有点
  • 芯片热阻的理解

    基本概念 xff1a Ta xff1a Temperature Ambient 环境温度 Tc xff1a Temperature Case外壳温度 Tj xff1a Temperature Junction节点温度 热阻Rja xff1a
  • HDC1080传感器使用

    HDC1080温湿度传感器的驱动链接 xff08 函数都封装好了 xff0c 稍微改改就能用了 xff09 xff1a https download csdn net download qq 27718231 12656947 没有积分的小
  • 日常所用的耳机接口定义

    耳机插座在我们日常生活中是比较常见的一种电子元件 xff0c 其耳机插座的类型规格也区分有四段式耳机插座 三段式耳机插座等 三段式和四段式耳机的引脚定义如下 xff1a 四段式耳机插座接线的方法 xff0c 其只是比一般三段式的耳机插座增加
  • SX1268 SX1262中文数据手册

    在使用SX1268的时候 xff0c 只有英文数据手册 xff0c 中文手册没有人翻译 xff0c 现提供SX1262的中文手册方便大家在开发SX1268程序时使用 xff0c 这两款芯片使用上几乎一样的 xff0c 只是SX1268支持中
  • 用IO口模拟串口(外部中断+定时器)--附程序附测试结果

    给大家分享一下我用IO口模拟串口的一种方法 xff0c 经测试使用这种方法发送能支持115200波特率 xff0c 接收9600波特率测试没问题 xff0c 接收波特率能否提高受制于用户应用场景是否能允许微妙级别的频繁中断了 xff0c 我