上回书搞定了串口,这次来尝试在Vscode+platformIO 里 Arduino 的开发环境下点亮OLED屏幕。
-硬件:这是一块0.96寸的OLED屏幕,有接排针,使用了4针,丝印标识了VCC、GND、SCL、SDA。所以是一块通过I2C通讯接口的oled屏幕。文档中没看见oled使用的是什么驱动,请教群里的老师得知,这是一块使用SSD1306驱动的128X64的单色oled屏幕。星允派 F103板子上预留了排母插座,看丝印是接到PB3、PB5的。

-扫描I2C接口:既然接口是I2C接口,按习惯,先扫描一下I2C接口上的硬件,看看是否能正常识别到硬件。 `
#include <Arduino.h>
#include <Wire.h>
#define PIN_SERIAL1_RX PA10
#define PIN_SERIAL1_TX PA9
HardwareSerial Serial1(USART1);
void setup()
{
Wire.begin();
pinMode(PIN_SERIAL1_RX, INPUT);
pinMode(PIN_SERIAL1_TX, OUTPUT);
Serial1.begin(115200);
Serial1.setRx(PIN_SERIAL1_RX);
Serial1.setTx(PIN_SERIAL1_TX);
}
void loop()
{
int nDevices = 0;
Serial1.println("Scanning...");
for (byte address = 1; address < 127; ++address)
{
Wire.beginTransmission(address);
byte error = Wire.endTransmission();
if (error == 0)
{
Serial1.print("I2C device found at address 0x");
if (address < 16)
{
Serial.print("0");
}
Serial1.print(address, HEX);
Serial1.println(" !");
++nDevices;
}
else if (error == 4)
{
Serial1.print("Unknown error at address 0x");
if (address < 16)
{
Serial1.print("0");
}
Serial1.println(address, HEX);
}
}
if (nDevices == 0)
{
Serial1.println("No I2C devices found\n");
}
else
{
Serial1.println("done\n");
}
delay(5000); // Wait 5 seconds for next scan
}
这里找到一个“0x50”的I2C的硬件设备,但是这个明显不是OLED屏幕,因为SSD1306的OLED屏幕,地址应该是"0X78"。在代码中按图索骥,默认的I2C接口是PB6、PB7。查看电路图,发现这里接了个AT24C02的存储芯片。这里有点疑惑,I2C总线是可以接多个设备的,这里为啥不把OLED接到PB6、PB7上去。
尝试直接修改代码中的I2C初始化的语句,将初始化时管脚映射到PB3、PB5上去。但结果是不行的,无法找到对应的oled设备,STM32不支持管脚的随意映射。
Wire.begin(PB5,PB3);
-使用U8G2的模拟I2C:既然oled的管脚没有接到stm32硬件I2C的管脚上,没关系,还可以使用软件模拟I2C方式。这里想用U8G2的库来驱动OLED屏幕,U8G2自身就有模拟I2C的支持。 `
#include <Arduino.h>
#include <U8g2lib.h>
#include <Wire.h>
// iic驱动方式
// U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/PB3, /* data=*/PB5, /* reset=*/U8X8_PIN_NONE); // 使用软件IIC,SCL PB3,SDA PB5
void
setup(void)
{
Serial.begin(115200);
u8g2.begin();
u8g2.enableUTF8Print(); // enable UTF8 support for the Arduino print() function
}
void loop(void)
{
u8g2.setFont(u8g2_font_unifont_t_chinese2); // use chinese2
u8g2.firstPage();
do
{
u8g2.setCursor(0, 20);
u8g2.print("helloworld 356"); // Chinese "Hello World"
u8g2.setCursor(40, 40);
u8g2.print("大千世界!"); // Chinese "Hello World"
} while (u8g2.nextPage());
delay(1000);
}
写了个简单的驱动OLED屏幕的例子,编译烧写,屏幕没反应!这让我很诧异,反复检查代码,代码没有问题。检查硬件连接,硬件连接正常。一度怀疑模块故障了。于是将同样的代码,烧录到另外一块 nucleo_f411re的开发板上,屏幕点亮。使用的相同的代码,相同的管脚,相同的屏幕硬件。唯一不同的就是开发板的不同。
在群里经过各位老师的指点,感觉应该是platformIO 的锅。只能感慨人生无常大肠包小肠。
-死磕到底:这里还是蛮疑惑的,其实单独控制PB3、PB5管脚的高低电平是没有任何问题的。就是不知道platformIO 是在哪个环节拉跨的。手头没有逻辑分析仪,否则看看是否有I2C信号能进一步确认问题的症结。不过既然控制管脚的高低电平没有问题,那么模拟I2C本身就是通过控制高低电平来模拟I2C的通讯协议的,所以手搓管脚的高低电平,用来模拟I2C的通讯,来驱动OLED应该也是可行的。网上找了一下软件模拟I2C的代码。
最终还是驱动起来了OLED,但是这样的软件模拟I2C就不知道如何和U8G2库相结合了,U8G2库里诸如显示汉字等方便的特性就无法实现了。最后将工程附上,看看哪位老师能解决platformIO的这个问题。
hello2.zip
下一个版本吧I2C引过来👍