- 什么是Bit Banging?
- 何时使用Bit Banging
- 通过位敲击进行串行通信的算法
- 通过SPI进行位冲击
- 位撞击的示例:Arduino中的SPI通信
- 位撞击的缺点
- UART通过Arduino中的位撞击
通信接口是选择用于项目的微控制器时要考虑的因素之一。设计人员确保所选的微控制器具有与该产品要使用的所有其他组件进行通信所需的所有接口。这些接口中某些接口(如SPI和I2C)在微控制器上的存在总是会增加此类微控制器的成本,并且取决于BOM预算,可能会使所需的微控制器负担不起。在这样的情况下,像位敲打这样的技术就会发挥作用。
什么是Bit Banging?
位冲击是一种串行通信技术,其中整个通信过程通过软件而不是专用硬件来处理。为了传输数据,该技术涉及使用软件将数据编码为信号和脉冲,这些信号和脉冲用于操纵微控制器的I / O引脚的状态,该微控制器的I / O引脚用作Tx引脚以将数据发送到目标设备。为了接收数据,该技术涉及在一定间隔后对Rx引脚的状态进行采样,该间隔由通信波特率确定。该软件设置实现该通信所需的所有参数,包括同步,时序,级别等,通常在不使用位敲打时由专用硬件决定。
何时使用Bit Banging
通常在无法使用具有所需接口的微控制器或切换到具有所需接口的微控制器的成本太高的情况下使用位边界。因此,它提供了一种使同一设备能够使用多种协议进行通信的廉价方法。以前只能用于UART通信的微控制器可配备通过位敲打使用SPI和12C进行通信。
通过位敲击进行串行通信的算法
虽然实现位撞的代码在不同的微控制器之间可能有所不同,并且对于不同的串行协议也可能有所不同,但是在所有平台上,实现位撞的过程/算法都是相同的。
例如,使用以下伪代码发送数据;
- 开始
- 发送起始位
- 等待时序与接收器的波特率相对应
- 发送数据位
- 等待持续时间再次与接收器的波特率相对应
- 检查是否已发送所有数据位。如果否,请执行4。如果是,请执行7
- 发送停止位
- 停止
接收数据往往要复杂一些,通常使用中断来确定何时接收器引脚上的数据可用。这有助于确保微控制器不会浪费太多的处理能力。尽管某些实现使用任何微控制器的I / O引脚,但如果不加处理,则产生噪声和错误的可能性会更高。下面说明使用中断接收数据的算法。
- 开始
- 启用Rx引脚上的中断
- 触发中断时,获取起始位
- 根据波特率等待时间
- 读取Rx引脚
- 从4开始重复,直到收到所有数据
- 根据波特率等待时间
- 检查停止位
- 停止
通过SPI进行位冲击
如上所述,不同协议的位敲击工作方式不同,因此在尝试实现每个协议之前,了解它们的数据帧和时钟非常重要。以SPI模式1为例,时钟的基值始终为0,并且始终在时钟的上升沿发送或接收数据。SPI模式1通信协议的时序图如下所示。
为了实现这一点,可以使用以下算法;
- 开始
- 将SS引脚设置为低电平以开始通信
- 将主输出从动输入(MOSI)的引脚设置为要发送的数据的第一位
- 将时钟引脚(SCK)设置为高电平,以便数据由主机发送并由从机接收
- 读取从机输出(MISO)的主机状态,以从机接收第一位数据
- 将SCK设置为低电平,以便可以在下一个上升沿发送数据
- 转到2,直到所有数据位都已发送。
- 将SS引脚设置为高电平可停止传输。
- 停止
位撞击的示例:Arduino中的SPI通信
作为示例,让我们通过Arduino中的位敲击实现SPI通信的算法,以显示如何使用下面的代码通过SPI对数据进行位敲击。
我们首先声明要使用的Arduino的引脚。
const int SSPin = 11; const int SCKPin = 10; const int MISOPin = 9; const int MOSIPin = 8; 字节sendData = 64; //要发送的值 字节slaveData = 0; //用于存储从站发送的值
接下来,我们转到 void setup() 函数,在该函数中声明引脚的状态。由于只有主机输入从机输出(MISO)引脚才是输入,因此它是唯一接收数据的引脚。所有其他引脚都声明为输出。声明引脚模式后,SS引脚设置为高电平。这样做的原因是为了确保该过程没有错误,并且仅在将其设置为低时才开始通信。
void setup() { pinMode(MISOPin,INPUT); pinMode(SSPin,OUTPUT); pinMode(SCKPin,OUTPUT); pinMode(MOSIPin,OUTPUT); digitalWrite(SSPin,HIGH); }
接下来,我们开始 循环 发送数据。请注意,此循环将继续重复发送数据。
我们通过将SS引脚写为低电平来启动 循环 ,以启动通信的开始,并调用 bitbangdata 函数,该函数将预定义的数据分解为多个位并发送。完成此操作后,我们将SS引脚写入HIGH,以指示数据传输结束。
void loop() { digitalWrite(SSPin,LOW); // SS低 slaveData = bitBangData(sendData); //数据传输 digitalWrite(SSPin,HIGH); // SS再次变高 }
所述 bitbangdata() 函数被写入的下方。该函数接收要发送的数据,并将其分解为多个位,然后通过循环传输代码进行发送,如算法步骤7所示。
byte bitBangData(byte _send)//此函数通过bitbanging { byte _receive = 0; for(int i = 0; i <8; i ++)//字节中的8位 { digitalWrite(MOSIPin,bitRead(_send,i)); //设置MOSI digitalWrite(SCKPin,HIGH); // SCK高 bitWrite(_receive,i,digitalRead(MISOPin)); //捕获MISO digitalWrite(SCKPin,LOW); // SCK低 } 返回_receive; //返回接收到的数据 }
位撞击的缺点
然而,采用位冲击应该是一个经过深思熟虑的决定,因为位冲击存在一些不利方面,可能使其在某些解决方案中的实现不可靠。由于该过程消耗的高处理能力,位撞击增加了微控制器消耗的功率。与专用硬件相比,使用位敲打时,尤其是当微控制器与其他任务同时执行数据通信时,会发生更多的故障,例如毛刺和抖动。通过位敲打进行通信的速度仅为使用专用硬件时的速度的一小部分。这在某些应用程序中可能很重要,并且可能会使“不那么好”的选择成为现实。
位撞击用于各种串行通信,包括:RS-232,异步串行通信,UART,SPI和I2C。
UART通过Arduino中的位撞击
位撞击的流行实现之一是Arduino软件串行库,它使Arduino能够通过UART进行通信,而无需使用专用的硬件UART引脚(D0和D1)。这提供了很大的灵活性,因为用户可以连接Arduino板上可以支持的尽可能多的引脚数量的串行设备。