IO口软件模拟串口

嵌入式工程师经常会遇到系统资源不够的情况,比如我就遇到了串口不够,但IO引脚和定时器还富余,这时就可以通过模拟方式来扩展出一个串口。

这个方法适用于所有嵌入式系统,但是要注意,对于速度不要设置得太高,尽量不要高于9600。否则,当串口所用到的资源优先级不够高,而系统又很繁忙的时候,容易丢失数据或出错。

软件IIC是同样的道理,用软件模拟相关时序,但是IIC对时序要求不高,相对容易

我做的是单总线SWI,即同一根线完成收和发,半双工方式运行。接收数据和发送数据不能同时。

串口时序

先说一下串口的时序,用得最多的就是9600,8,N,1,解释一下:
起始位1,在配置描述中中省略,低电平。
9600是波特率,即每秒产生的位数。也有些设备是9600或更低。
8:数据位是8位
N:无
1:1个停止位,高电平
以9600,8,N,1为例,整个时序如下:
IO口软件模拟串口_第1张图片
串口空闲时默认为高电平,当有一个低电平到来时,表示收到起始位,然后依次是8个数据位,接着收到1个高电平,每个位的宽度为104微秒。
串口的波特率误差容忍为5%以内,为什么呢?其实很简单,串口的数据采样是在每个数据位的中心位置,即50%处采样,而一个数据帧有10位(1起始,8数据,1停止,无校验),即每个数据位只能允许5%的误差。如果你的软件工作时经常被中断打断,而中断执行的时间又比较长,那么只能选择更低的波特率,或者干脆放弃软件模拟这种方式。

发送数据

发送数据很简单,按照上图时序依次发出就行。以发送一个字节为例,u8 data = 0xa3

  • 1、将这个IO口(以PA0为例),配置为开漏输出,上拉,输出为1。
  • 2、配置定时器的溢出周期为104微秒,9600的倒数。
  • 3、启动定时器
  • 4、在定时器的中断中执行以下内容:
    • 第1次进中断:PA0 = 0;
    • 第2~9次进中断:
      • PA = 0x01&data;
      • data >>= 1; //共右移8次
    • 第10次进中断:PA0 = 1;
    • 第11次进中断:关定时器
    • 发送完成

接收数据

IO口软件模拟串口_第2张图片接收数据要麻烦一些,不过也不难,按上图来。

  • 1、将这个IO口(以PA0为例),配置为输入EXTI模式,上拉,输出为1,这样不影响输入。
  • 2、配置定时器的溢出周期为52微秒。即为输出时定时器周期的一半时间。
  • 3、PA0为低时,触发中断,此时EXTI中断,并启动定时器
  • 4、定时器中断中执行如下操作
    • 偶数次中断直接退出,因为此时对应的是电平变化的时刻,无法读取电平
    • 第1次进中断:多次读取PA0的电平状态,均为0时表示正确收到低电平,可以执行后续数据读取操作,否则收到是毛刺信号,退出即可。重置为初始接收状态。
    • 第3~17次奇数中断,多次读取PA0的电平,多数值为1,即认为收到高电平,否则认为收到低电平。如果是高电平:buf = (buf|0x80)>>1,低电平时,buf >>=1。注意,移位操作需要进行7次,而不是8次
    • 第19次进中断:多次读取PA0的电平,
      • 多数值为1,此时关定时器,并开启EXTI中断,接收正常完成。
      • 多数值为0,表示帧结束错误,此时关定时器,并开启EXTI中断,进行错误处理流程。这一步也可以不处理,认为收到的数据正确即可。
    • 接收完成

你可能感兴趣的:(嵌入式开发,stm32,嵌入式,单片机,串口通信)