在本教程中,我们将使用 STM32F103C8 的 Blue Pill 板替换一个 Arduino 板,并将使用 SPI 总线与 Arduino 板进行通信。在这个STM32 SPI 示例中,我们将使用Arduino UNO作为 Slave,STM32F103C8 作为 Master,两个16X2 LCD 显示器分别连接在一起。两个电位器还与STM32(PA0)和Arduino(A0)相连,通过改变电位器来确定主机到从机和从机到主机的发送值(0到255)。
STM32F103C8中的SPI
比较 Arduino 和 STM32F103C8 Blue Pill 板中的 SPI 总线,STM32 有2 条 SPI 总线,而 Arduino Uno 有1 条 SPI 总线。Arduino Uno 有 ATMEGA328 微控制器,STM32F103C8 有 ARM Cortex-M3,比 Arudino Board 更快。
STM32 SPI 引脚 STM32F103C8
Arduino 中的 SPI 引脚
所需组件
STM32F103C8
阿杜诺
液晶 16x2 - 2
10k 电位器 – 4
面包板
连接电线
STM32 SPI教程的电路图和连接
下表显示了STM32 SPI与 Arduino 通信连接的引脚。
下表显示了两个 LCD (16x2) 分别与 STM32F103C8 和 Arduino连接的引脚。
重要的:
不要忘记将 Arduino GND 和 STM32F103C8 GND 连接在一起。
STM32 SPI编程
编程类似于 Arduino 代码。在 STM32F103C8 编程中使用了相同的《SPI.h》库。它可以在不使用 FTDI 编程器的情况下使用 USB 端口进行编程,要了解有关 使用 Arduino IDE 对 STM32 进行编程的更多信息,请 点击链接。
Master STM32 SPI编程讲解
1.首先我们需要 包含 使用SPI通信功能的SPI库和使用LCD功能的LCD库。还为 16x2 LCD 定义 LCD 引脚。在此处了解有关LCD 与 STM32 接口的 更多信息。
#include
#include
const int rs = PB0, en = PB1, d4 = PB10, d5 = PB11, d6 = PC13, d7 = PC14;
LiquidCrystal lcd(rs,en,d4,d5,d6,d7);
2. 在 void setup()
以波特率 9600 开始串行通信。
序列号.开始(9600);
接下来开始SPI通信
SPI.开始();
然后为 SPI 通信设置时钟分频器。我设置了分隔线 16。
SPI.setClockDivider(SPI_CLOCK_DIV16);
接下来将 SS 引脚设置为高电平,因为我们没有开始向从 arduino 进行任何传输。
数字写入(SS,HIGH);
3. 在void loop()
在向从机发送任何值之前,我们需要降低从机选择值以开始从主机传输到从机。
数字写入(SS,低);
接下来从连接到引脚 PA0 的主控 STM32F10C8 POT 读取模拟值。
int pot = 模拟读取(PA0);
然后将该值转换为一个字节(0 到 255)。
字节 MasterSend = map(pot,0,4096,0,255);
这是重要的一步,在下面的语句中,我们将存储在Mastersend变量中的转换后的 POT 值发送到从 Arduino,并从从 Arduino 接收值并将其存储在mastereceive变量中。
Mastereceive = SPI.transfer(Mastersend);
接下来以 500 微秒的延迟显示从从 arduino 接收到的值,然后连续接收并显示这些值。
Serial.println("从 Arduino 到主 STM32"); Serial.println(MasterReceive lcd.setCursor(0,0); lcd.print("Master: STM32"); lcd.setCursor(0,1); lcd.print("SalveVal:"); lcd.print(MasterReceive delay (500); 数字写入(SS,高);
注意:我们使用 serial.println() 在 Arduino IDE 的 Serial Motor 中查看结果。
从机 Arduino SPI 编程说明
1.和master一样,首先我们需要 包含使用I2C通信功能的SPI库 和使用LCD功能的LCD库。还为 16x2 LCD 定义 LCD 引脚。
#include
#include
LiquidCrystal lcd(2, 3, 4, 5, 6, 7); // 定义 LCD 模块引脚 (RS,EN,D4,D5,D6,D7)
2. 在 void setup()
我们以波特率 9600 开始串行通信。
序列号.开始(9600);
下面的语句将 MISO 设置为 OUTPUT(必须将数据发送到 Master IN)。因此数据通过 Slave Arduino 的 MISO 发送。
pinMode(味噌,输出);
现在通过使用 SPI 控制寄存器在从模式下打开 SPI
SPCR |= _BV(SPE);
然后为 SPI 通信打开中断。如果从主机接收到数据,则调用中断服务程序并从 SPDR(SPI 数据寄存器)中获取接收到的值
SPI.attachInterrupt();
master 的值取自 SPDR 并存储在Slavereceived变量中。这发生在以下中断例程函数中。
中断服务程序(SPI_STC_vect) { 从机接收 = SPDR; 收到=真; }
3.next in void loop()
从连接到引脚 A0 的 Slave Arduino POT 读取模拟值。
int pot = 模拟读取(A0);
将该值以一个字节为单位转换为 0 到 255。
Slavesend = map(pot,0,1023,0,255);
下一个重要步骤是将转换后的值发送到主控 STM32F10C8,因此将值放入 SPDR 寄存器。SPDR 寄存器用于发送和接收值。
SPDR = 从发送;
然后以 500 微秒的延迟在 LCD 上显示从主控 STM32F103C8 接收到的值(SlaveReceive),然后连续接收并显示这些值。
lcd.setCursor(0,0); lcd.print("奴隶:阿杜诺"); lcd.setCursor(0,1); lcd.print("MasterVal:"); Serial.println("主 STM32 到从 Arduino"); Serial.println(SlaveReceived); lcd.print(SlaveReceived); 延迟(500);
通过 旋转一侧的电位器,您可以在另一侧的 LCD 上看到不同的值:
这就是 STM32 中 SPI 通信的方式。现在您可以将任何 SPI 传感器与 STM32 板连接。
//STM32F103C8的SPI Master代码
//STM32和Arduino之间的SPI通信
#include // 包含使用 SPI 通信的库
#define SS PA4
#include // 包括LCD显示库
const int rs = PB0, en = PB1, d4 = PB10, d5 = PB11, d6 = PC13, d7 = PC14; // 声明 lcd 的管脚名称和管脚编号
LiquidCrystal lcd(rs,en,d4,d5,d6,d7); // 设置 lcd 及其参数
无效设置(无效)
{
lcd.begin(16,2); // 设置 lcd 为 16x2 模式
lcd.setCursor(0,0); // 在第一行第一列设置光标
lcd.print("CIRCUIT DIGEST"); // 将 CIRCUIT DIGEST 放入 LCD
延迟(3000);// 延迟 3 秒
lcd.clear(); // 清除液晶显示器
Serial.begin(9600); // 以波特率 9600 开始串行通信
pinMode(SS,输出);// 将 SS 作为输出
SPI.begin(); // 开始 SPI 通信
SPI.setClockDivider(SPI_CLOCK_DIV16); // 将 SPI 通信的时钟设置为 16 (72/16=4.5Mhz)
digitalWrite(SS,HIGH); // 将 SlaveSelect 设置为 HIGH(所以 master 不与 slave 连接)
}
无效循环(无效)
{
字节MasterSend,MasterReceive;
int pot = 模拟读取(PA0);// 模拟读取引脚 PA0 的输入电位器值
MasterSend = map(pot,0,4096,0,255); // 用于将 0 到 255 的罐值从 0 转换为 4096
digitalWrite(SS, LOW); // 开始与连接到主控的从属通信
MasterReceive=SPI.transfer(MasterSend); // 将 mastersend 值发送到 slave 也从 slave 接收值
Serial.println("Slave Arduino to Master STM32"); // 用于串行监视器
Serial.println(MasterReceive); // 将接收到的值放入串行监视器
lcd.setCursor(0,0);
lcd.print("主控:STM32");
lcd.setCursor(0,1);
lcd.print("SalveVal:");
lcd.print(MasterReceive); // 将接收到的值从 slave arduino
delay(500);
数字写入(SS,高);// 再次将 SS 线设为高电平,使其不与从属
lcd.clear() 通信;
}
从 Arduino SPI
//Arduino的SPI从代码
//STM32F103C8和Arduino之间的SPI通信
//电路文摘
#include // 包括使用 SPI 通信的库
#include // 包括 LCD 显示库
LiquidCrystal lcd(2, 3, 4, 5, 6, 7); // 定义 LCD 模块引脚 (RS,EN,D4,D5,D6,D7)
接收到的易失布尔值;
易失字节SlaveReceived,Slavesend;
无效设置()
{
lcd.begin(16,2); // 初始化 LCD 显示
lcd.setCursor(0,0); // 在 Display 的第一行设置光标
lcd.print("CIRCUIT DIGEST"); // 在 LCD
delay(3000) 中打印 CIRCUIT DIGEST;// 延迟 3 秒
lcd.clear(); // 清除 LCD 显示
Serial.begin(9600); // 以波特率 9600 开始串行通信
pinMode(MISO,OUTPUT); // 将 MISO 设置为 OUTPUT(必须向 Master IN 发送数据(STM32F103C8)
SPCR |= _BV(SPE); // 在从机模式下打开 SPI
received = false;
SPI.attachInterrupt(); // 为 SPI 通信设置 Interuupt ON
}
ISR (SPI_STC_vect) // Inerrrput 例程函数
{
SlaveReceived = SPDR; // 从主控STM32F103C8接收的值存储在变量slavereceived
received = true; // 设置接收为 True
}
无效循环()
{
int pot =模拟读取(A0);// 模拟从模拟引脚 A0 读取输入电位器值
Slavesend = map(pot,0,1023,0,255); // 将值 pot (0-1023) 转换为 (0-255) 以发送到主控 stm32
SPDR = Slavesend; // 通过 SPDR 将 salvesend 值发送给主控 STM32F103C8
lcd.setCursor(0,0);
lcd.print("奴隶:阿杜诺");
lcd.setCursor(0,1);
lcd.print("MasterVal:");
Serial.println("主 STM32 到从 Arduino");
Serial.println(SlaveReceived);
lcd.print(SlaveReceived); // 将从主控 STM32F103C8 接收到的值置于 LCD 显示
延迟(500)处;
lcd.clear();
}