一、代码路径
上一篇末尾更新了代码路径
https://github.com/Kunlun-Donkey/desktop-dog-Bruce.git
可以使用git命令去下载到本地:
git clone https://github.com/Kunlun-Donkey/desktop-dog-Bruce.git
这一篇我们使用git down下来的代码去完成点灯操作,验证OK后添加驱动代码,添加软件i2c的驱动代码和oled的显示接口
IO引脚如下
#define SDA_Pin GPIO_PIN_4
#define SDA_GPIO_Port GPIOA
#define SCL_Pin GPIO_PIN_5
#define SCL_GPIO_Port GPIOA
二、下载后的代码编译通过后尝试电灯操作
使用PB0点了一个灯看起来是OK的,代码工程没啥问题
while (1)
{
/* USER CODE END WHILE */
/* Test GPIOB0 LED, Set hight level */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
/* USER CODE END 3 */
}
/* USER CODE END 3 */
三、添加OLED驱动代码
我们使用0.96寸四引脚OLED作为显示屏,用来显示表情或者图片等信息,0.96寸OLED使用1306作为驱动芯片,支持I2C驱动和OLED驱动,为了简单我们使用I2C驱动,HAL库里面有I2C的驱动库,可以快速开发OLED代码。新增代码如下。
// OLED.c
// Send command to OLED
static void OLED_Write_Command(uint8_t command) {
Soft_I2C_Start();
Soft_I2C_Write(OLED_I2C_ADDRESS);
Soft_I2C_Write(0x00);
Soft_I2C_Write(command);
Soft_I2C_Stop();
}
// Send data to OLED
static void OLED_Write_Data(uint8_t data) {
Soft_I2C_Start();
Soft_I2C_Write(OLED_I2C_ADDRESS);
Soft_I2C_Write(0x40);
Soft_I2C_Write(data);
Soft_I2C_Stop();
}
void OLED_Init(void) {
Soft_I2C_Init();
// Initialization sequence for SSD1306
OLED_Write_Command(0xAE); // Display off
OLED_Write_Command(0x20); // Set Memory Addressing Mode
OLED_Write_Command(0x10); // 00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
OLED_Write_Command(0xB0); // Set Page Start Address for Page Addressing Mode,0-7
OLED_Write_Command(0xC8); // Set COM Output Scan Direction
OLED_Write_Command(0x00); // ---set low column address
OLED_Write_Command(0x10); // ---set high column address
OLED_Write_Command(0x40); // --set start line address
OLED_Write_Command(0x81); // --set contrast control register
OLED_Write_Command(0xFF);
OLED_Write_Command(0xA1); // --set segment re-map 0 to 127
OLED_Write_Command(0xA6); // --set normal display
OLED_Write_Command(0xA8); // --set multiplex ratio(1 to 64)
OLED_Write_Command(0x3F); //
OLED_Write_Command(0xA4); // 0xa4,Output follows RAM content;0xa5,Output ignores RAM content
OLED_Write_Command(0xD3); // -set display offset
OLED_Write_Command(0x00); // -not offset
OLED_Write_Command(0xD5); // --set display clock divide ratio/oscillator frequency
OLED_Write_Command(0xF0); // --set divide ratio
OLED_Write_Command(0xD9); // --set pre-charge period
OLED_Write_Command(0x22); //
OLED_Write_Command(0xDA); // --set com pins hardware configuration
OLED_Write_Command(0x12);
OLED_Write_Command(0xDB); // --set vcomh
OLED_Write_Command(0x20); // 0x20,0.77xVcc
OLED_Write_Command(0x8D); // --set DC-DC enable
OLED_Write_Command(0x14); //
OLED_Write_Command(0xAF); // --turn on oled panel
}
void OLED_Clear(void) {
for (uint8_t i = 0; i < 8; i++) {
OLED_Write_Command(0xB0 + i); // Set page address
OLED_Write_Command(0x00); // Set low column address
OLED_Write_Command(0x10); // Set high column address
for (uint8_t j = 0; j < 128; j++) {
OLED_Write_Data(0x00);
}
}
}
void OLED_Display_On(void) {
OLED_Write_Command(0x8D); // Set DC-DC enable
OLED_Write_Command(0x14); //
OLED_Write_Command(0xAF); // Display ON
}
void OLED_Display_Off(void) {
OLED_Write_Command(0x8D); // Set DC-DC disable
OLED_Write_Command(0x10); //
OLED_Write_Command(0xAE); // Display OFF
}
void OLED_Set_Pos(uint8_t x, uint8_t y) {
OLED_Write_Command(0xB0 + y);
OLED_Write_Command(((x & 0xF0) >> 4) | 0x10);
OLED_Write_Command((x & 0x0F) | 0x01);
}
void OLED_ShowChar(uint8_t x, uint8_t y, char chr) {
// Implement character display function
}
void OLED_ShowString(uint8_t x, uint8_t y, char *chr) {
// Implement string display function
}
void OLED_ShowImage(uint8_t x, uint8_t y, const uint8_t *image, uint8_t width, uint8_t height) {
for (uint8_t i = 0; i < height / 8; i++) {
OLED_Set_Pos(x, y + i);
for (uint8_t j = 0; j < width; j++) {
OLED_Write_Data(image[i * width + j]);
}
}
}
void OLED_ShowGIF(const uint8_t **frames, uint8_t frame_count, uint8_t width, uint8_t height, uint16_t delay) {
for (uint8_t i = 0; i < frame_count; i++) {
OLED_ShowImage(0, 0, frames[i], width, height);
HAL_Delay(delay);
}
}
软件I2C代码
#include "soft_i2c.h"
#include "gpio.h"
#define SDA_HIGH() HAL_GPIO_WritePin(SDA_GPIO_Port, SDA_Pin, GPIO_PIN_SET)
#define SDA_LOW() HAL_GPIO_WritePin(SDA_GPIO_Port, SDA_Pin, GPIO_PIN_RESET)
#define SCL_HIGH() HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_SET)
#define SCL_LOW() HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_RESET)
#define SDA_READ() HAL_GPIO_ReadPin(SDA_GPIO_Port, SDA_Pin)
void Soft_I2C_Delay(void) {
for (volatile int i = 0; i < 100; i++);
}
void Soft_I2C_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
// Configure SDA and SCL pins as open-drain
GPIO_InitStruct.Pin = SDA_Pin | SCL_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(SDA_GPIO_Port, &GPIO_InitStruct);
SDA_HIGH();
SCL_HIGH();
}
void Soft_I2C_Start(void) {
SDA_HIGH();
SCL_HIGH();
Soft_I2C_Delay();
SDA_LOW();
Soft_I2C_Delay();
SCL_LOW();
}
void Soft_I2C_Stop(void) {
SDA_LOW();
SCL_HIGH();
Soft_I2C_Delay();
SDA_HIGH();
Soft_I2C_Delay();
}
void Soft_I2C_Write(uint8_t data) {
for (int i = 0; i < 8; i++) {
if (data & 0x80) {
SDA_HIGH();
} else {
SDA_LOW();
}
data <<= 1;
SCL_HIGH();
Soft_I2C_Delay();
SCL_LOW();
Soft_I2C_Delay();
}
SDA_HIGH();
SCL_HIGH();
Soft_I2C_Delay();
SCL_LOW();
}
uint8_t Soft_I2C_Read(uint8_t ack) {
uint8_t data = 0;
SDA_HIGH();
for (int i = 0; i < 8; i++) {
SCL_HIGH();
Soft_I2C_Delay();
data = (data << 1) | SDA_READ();
SCL_LOW();
Soft_I2C_Delay();
}
if (ack) {
SDA_LOW();
} else {
SDA_HIGH();
}
SCL_HIGH();
Soft_I2C_Delay();
SCL_LOW();
SDA_HIGH();
return data;
}
有一点需要注意的,开启stm32f1xx_hal_conf.h中的使能HAL_I2C_MODULE_ENABLEd去使能的I2C是硬件I2C,我们建议还是使用软件I2C方便点,我的代码提交记录最新的是软件i2c,soft_i2c.c