本帖最后由 dffzh 于 2025-4-2 16:19 编辑
#申请原创#
@21小跑堂
在MCU硬件资源(包括总线资源和引脚资源等)受限时,如果需要使用SPI总线进行MCU和外围器件的通信,在硬件SPI损坏或缺失的情况下,可以考虑使用软件模拟SPI总线,即通过普通的GPIO引脚的电平翻转和延时操作实现SPI数据的读取和写入。 以下实现模拟SPI的功能已在AT32F403ACCT7平台上成功验证。 首先你需要对4个GPIO引脚进行普通输入输出模式的配置,即CS信号-PB6脚,CLK信号-PB7脚,MOSI信号-PB9脚,MISO信号-PB8脚,如下图所示: 其次你需要实现数据的读取和写入操作,我的这个demo例程是通过IS3980S芯片实现数字量信号的读取操作,即MCU和IS3980S之间以模拟SPI方式实现数据读写操作,所以变量等的命名基本上都带有“IS3980S”字符串,但这毫无影响,以下是GPIO的定义实现: 对于MCU输出的引脚,定义了输出高电平或低电平的宏; 对于MCU输入的引脚,定义了读取外部电平信号的宏。
另外,定义了非精确的延时操作函数和延时时间,如下图:
IS3980S_DELAY_TIME为延时时间,决定了模拟SPI的时钟频率,其值越小,时钟频率越大,而能支持的最大时钟频率由MCU主频决定。在实际项目开发时,需要通过使用示波器抓取CLK信号的波形来判断波形失真情况,以及根据硬件上设计的RC滤波电路来计算截止频率,加上产品规格需求,基本上就能判断出来模拟SPI设计是否能符合项目需求。
对于读取函数,即MCU从外围器件读取数据,主要原理是在操作CS信号为低电平期间,通过控制CLK信号并在其上升沿或下降沿时刻(demo为上升沿,参考器件手册)读取MISO信号的电平,并存储到8位无符号变量read_byte里面,主要代码如下所示 : 读取函数的返回值read_byte即为读取到的一个字节数据。
对于写入函数,即MCU向外围器件写入数据,函数入参write_byte即为需要写入的一个字节数据,主要原理是在操作CS信号为低电平期间,通过控制CLK信号并在其上升沿或下降沿时刻(demo为上升沿,参考器件手册)输出MOSI为高电平或低电平,主要代码如下所示: 模拟SPI应用场景很多,相对于硬件SPI,以下对两者的优缺点进行了简单说明,大家可以根据实际应用场景和需求进行选择。 模拟SPI 优点: 移植性强:如以上代码所示,一般只需要修改底层驱动配置,即可在其他MCU上使用; 灵活性高:普通GPIO即可实现,在SPI总线资源不够时可以考虑。 缺点: 处理器负载高:需要频繁地控制GPIO电平翻转; 传输速度慢:受MCU主频和GPIO电平翻转速度影响。
硬件SPI 优点: 传输速度快:能够达到几十MHz的速度,适合实时性要求较高的场合; 处理器负载低:使用硬件模块进行通信,执行效率高。 缺点: 成本较高:需要专门的硬件模块,增加成本; 灵活性较低:硬件SPI模块损坏后,就无法实现SPI总线通信。
|