目录
3.1.3 时钟树设置(Clock Configuration)
前言
文章为记录个人学习HAL库的成果,使用的芯片型号为:STM32F103C8T6,使用辅助软件:CubeMx,这篇文章是对江协标准库OLED进行移植,所用到的OLED文件来源于江协。参考的视频来源于B站up主野生绿波电龙,视频的BV号为:BV1jr421L7kU
以及B站up主江协科技,视频的BV号为:BV1th411z7sn
以及B站up主成电应电科协,视频BV号为:BV1y7411m7gg
一、为什么要移植OLED?
OLED作为单片机数据显示的一个外设,我们可以把各类参数显示在OLED上面,就比如可以把
STM32F103C8T6与OpenMv通信过程的关键信息显示在OLED上,这样我们可以通过单片机接收到的数据对其进行下一步的判断、处理;也可以作为检验代码是否出错的排查工具。因此,OLED对于单片机而言,其功能十分重要。
二、对移植过程的思考
2.1 江协代码的粗略分析
打开江协的代码,我们可以发现关于OLED有三个函数,分别为:OLED.c,OLED.h,OLED_Font.h
查看江协的OLED.c的代码,我们会发现他是用软件模拟IIC通信来进行的,我们可以将要修改代码分为两个部分:
第一部分是模拟IIC中定义时钟总线和数据总线,第二部分是引脚的初始化操作。
2.1.1 对第一部分的江协代码进行分析
这是一个define的宏定义,是对GPIO口进行写入的操作。这时候我看到了“BitAction”,这是啥玩意?字面意思是bit行动?我进行了如下操作。
对“BitAction”进行选中,找到它定义的地方,可以发现它是一个结构体:
因此我们就可以知道它的作用了,它的作用是对端口进行使能或不使能。而BitAction(x)则可以通过x的取值来选择其为使能或不使能。
2.1.2 对第二部分的江协代码进行分析
第二部分倒是更方便理解,由于其是对GPIO口的初始化,我们可以在之后的CubeMx中直接对其进行配置。值得注意的是“GPIO_Speed”的部分,江协将单片机端口的速度设置成了50MHZ,对应HAL库的速度选值我们可以参考下表(来源于成电应电科协视频P43的4分15秒处)
因此在配置引脚输出速度时可以选用“MEDIUM”
2.2 江协代码与HAL库的区别
在江协代码的第一部分中,我们会发现“GPIO_WriteBit(GPIOB, GPIO_Pin_8, (BitAction)(x))”的这种格式与HAL库的格式不相符,HAL对于GPIO口写入的格式应该为“HAL_GPIO_WritePin(GPIOx,GPIO_PIN_x,GPIO_PIN_SET(或者是GPIO_PIN_RESET))”,因此我们在移植的时候首先要对其进行改写。
那么在HAL库中有没有像标准库那样“BitAction”的结构体对GPIO端口进行使能或不使能操作呢?在标准库中,我们发现“BitAction”所存放的位置是“stm32f10x_gpio.h”中。
那么在HAL库中有没有类似的文件呢?我去翻了翻HAL的gpio口的文件,发现有和“BitAction”类似功能的函数,它在HAL库中名字为“GPIO_PinState”,被存放在“stm32f1xx_hal_gpio.h”中。
因此我们在HAL库中要把“BitAction”替换为“GPIO_PinState”。
三、进行移植
3.1 CubeMx配置
3.1.1 选择芯片型号
打开CubeMx软件:
在搜索框中输入芯片型号“STM32F103C8”,并选择该型号:
3.1.2 System Core配置
点击“SYS”,将Debug选择为“Serial Wire”,其余地方保持默认设置即可,不用更改。
点击“RCC”,将“High Speed Clock(HSE)”选择为“Crystal/Ceramic Resonator”,其余地方保持默认设置即可,不用更改。
点击芯片的“PB8”引脚,选择“GPIO_Output”(PB9同理)
点击"GPIO",再点击"PB8",将“GPIO mode”设置为开漏输出模式(Output Open Drain),速度选择“Medium”,“PB9”的设置与“PB8”的设置一样,这里就不重复赘述了。
3.1.3 时钟树设置(Clock Configuration)
点击“Clock Configuration”,将框中的“8”修改为“72”,然后按下回车键,
在弹出来的框中选择“OK”
3.1.4 Project Manager设置
输入项目名称“OLED”,将“EWARM”改为“MDK-ARM”
版本更改为V5
点击“Code Generator”,勾选图片第二个框中的内容(这是用于生成对应的.c和.h文件的),然后点击“GENERATE CODE”生成代码
点击“Open Project”打开keil5
3.2 代码编写
3.2.1 将程序设置为自启动模式
点击菜单栏中的“魔术棒”
点击“Debug”,然后再点击“Settings”
点击“Flash Download”,勾选选项“Reset and Run”,再点击“确定”
3.2.2 创建自己的文件夹
创建自己的文件夹可以区别于CubeMx生成代码时创建的文件夹,更为方便管理。
打开文件路径,创建一个新文件夹“MyUsed”
文件路径位置每个人不一定相同,可以根据自己的CubeMx中的这个位置来定位(这里我的文件路径的位置是在F盘,STM32文件夹下的CubeMx文件夹,CubeMx文件夹下的test文件夹,test文件夹下的OLED文件夹,请根据自己的位置来定位文件夹路径):
把江协的三个关于OLED的代码复制到“MyUsed”文件夹下
打开keil5,按照下面四步进行操作
在刚刚创建好的“MyUsed”文件夹,右击鼠标
点击“向上一级”
把文件类型改为“All files”,之后打开“MyUsed”
按住鼠标左键,将三个OLED代码全部选中后点击“Add”,添加完成后点击“Close”关闭标签页
此时三个文件就被加入到Keil5所创建的文件夹“MyUsed”中了,但它的路径还未添加,keil5无法识别,接下来是添加路径:
点击魔术棒,再点击“C/C++”,然后点击三个小点
点击文件夹图标,再点击三个小点
返回文件的上一级
点击“MyUsed”,选中后点击“选择文件夹”
点击“OK”,再点击“OK”
自此,创建自己的文件夹就完成了。
3.2.3 开始移植,修改江协代码
打开keil5左侧的“MyUsed”文件夹中的OLED.c,将头文件处“#include "stm32f10x.h"改为“#include gpio.h”;将“GPIO_WriteBit”替换为“HAL_GPIO_WritePin”;将“GPIO_Pin”改为“GPIO_PIN”;将“BitAction"替换为“GPIO_PinState”。结果如下所示:
#include "gpio.h"
#include "OLED_Font.h"
/*引脚配置*/
#define OLED_W_SCL(x) HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,(GPIO_PinState)(x))
#define OLED_W_SDA(x) HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,(GPIO_PinState)(x))
对引脚初始化函数“void OLED_I2C_Init(void)”进行修改,将标准库对引脚的初始化改为CubeMx自动生成的引脚初始化,即:
/*引脚初始化*/
void OLED_I2C_Init(void)
{
MX_GPIO_Init();
OLED_W_SCL(1);
OLED_W_SDA(1);
}
添加OLED的头文件,打开main.c文件,在“ /* USER CODE BEGIN Includes */ ”和“ /* USER CODE END Includes */ ”之间添加头文件#include "OLED.h"
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "OLED.h"
/* USER CODE END Includes */
初始化OLED,在“ /* USER CODE BEGIN SysInit */ ”和“ /* USER CODE END SysInit */ ”之间添加“OLED_Init();”
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
OLED_Init();
/* USER CODE END SysInit */
开始测试在OLED上显示数据,在“ /* USER CODE BEGIN 2 */ ”和“ /* USER CODE END 2 */ ”之间写入代码:
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
OLED_Init();
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
OLED_ShowChar(1, 1, 'A');
OLED_ShowString(1, 3, "HelloWorld!");
OLED_ShowNum(2, 1, 12345, 5);
OLED_ShowString(3, 1, "NaOH");
/* USER CODE END 2 */
至此,OLED的移植就结束了。
四、移植后的效果图
总结
移植完OLED后可以用于之后的串口通信部分,来检查数据的收发是否有问题,对我而言还是挺有帮助的,这也正是我移植OLED的目的之一。OLED相较于单片机就好似printf相较于C语言,如果没有printf,C语言的学习将会很困难,你无法对代码进行测试,OLED的作用就在于此。
参考文献
[1] 成电应电科协. (2020, March 24). 【STM32教程】入门教程(基于HAL库+CubeMX+MDK-ARM) [Video]. Retrieved from https://www.bilibili.com/video/BV1y7411m7gg?p=43
[2] breeze0321. (2022, April 4). STM32F103c8t6 - CubeMX 快速实现时钟配置 - 最大72M时钟的设定及实验测试. CSDN博客. <https://blog.csdn.net/weixin_43604457/article/details/123262730>
[3] 野生绿波电龙. (2024, May 19). P3.移植江协OLED显示屏【HAL库复现江协全部STM32例子合集】 [Video]. Retrieved from https://www.bilibili.com/video/BV1jr421L7kU/?spm_id_from=333.788
[4] 江协科技. (2021, July 29). STM32入门教程-2023版 细致讲解 中文字幕 [Video]. Retrieved from