提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
提示:本文仅供学习和参考:
本篇开始基于STM32单片机开发一个平衡小车的项目软件篇,软件上会用到CubeMX全家桶,下面介绍如何使用CubeMX搭建项目,以及如何在此基础上编写驱动。
一、搭建过程
- 使用CubeMX新建项目, 完成MCU选型, 本次MCU使用的是STM32F103C8T6, 如下
- 配置好系统时钟,我们选择外部晶振提供的高速时钟,以及基础的GPIO,PC13用于后面的LED控制,如下:
- 配置时钟树,我们输出系统时钟配置成最高支持的72MHz后回车,如下:
- 最后完成项目名设置和设置,点击生成项目,我们推荐如下设置:
- 打开项目,完成全局编译,目录结构如下:
二、编写驱动
1. LED控制
本次要控制的LED引脚是PC13,低电平点亮,高电平熄灭。前面我们已经初始化硬件,创建好对应的头文件和源文件,通过HAL库配置高低电平。下面代码中实现系统在上电时候,LED闪烁,最后熄灭的,开始进行后续校准。
#include "led.h"
void Set_LED_Off()
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
}
void Set_LED_On()
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
}
void Blink_LED()
{
int i;
for(i=0; i<6; i++){
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
HAL_Delay(500);
}
}
在main
函数调用:
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
if(Init_System_Flag < 1)
{
Blink_LED();
Init_System_Flag += 1;
Set_LED_Off();
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
2. OLED屏幕驱动
本次OLED显示屏用的是SSD1306驱动芯片,通过I2C通信接口通信,对应的硬件接口是PB8和PB9。重新打开CubeMX, 开启I2C1,然后生成代码。
OLED屏幕驱动芯片通过写命令和写数据来控制显示,写命令主要是做一些清屏,背光颜色对比度之类的动作,写数据是在LED屏幕上显示字符串。在Hal库里面,我们可以通过HAL_I2C_Mem_Write
函数完成I2C的写操作,从而完成写命令和写数据。
void Oled_Write_CMD(uint8_t cmd){
HAL_I2C_Mem_Write(&hi2c1 ,0x78,0x00,I2C_MEMADD_SIZE_8BIT,&cmd,1,0x100);
}
void Oled_Write_Data(uint8_t data){
HAL_I2C_Mem_Write(&hi2c1 ,0x78,0x40,I2C_MEMADD_SIZE_8BIT,&data,1,0x100);
}
在上面代码中0x78
对应的是设备的I2C地址,在完成写命令的操作时候,对应的内存寄存器地址是0x00
,写数据的内存地址是0x40
, 都是写入1个字节。
对于OLED屏幕的使用步骤,如下:
- 初始化:
通过写命令的方式,逐一发送相关设置,完成LED的配置以及打开显示
uint8_t Init_Settings[] = {
0xAE, // 关闭显示
0xD5, 0x80, // 设置显示时钟分频和振荡器频率
0xA8, 0x3F, // 设置多路复用率
0xD3, 0x00, // 设置显示偏移
0x40, // 设置显示起始行
0x8D, 0x14, // 启用电荷泵
0x20, 0x00, // 设置内存地址模式(水平地址模式)
0xA1, // 设置段重映射(列地址 127 映射到 SEG0)
0xC8, // 设置 COM 输出扫描方向(从 COM[N-1] 到 COM0)
0xDA, 0x12, // 设置 COM 引脚硬件配置
0x81, 0xCF, // 设置对比度
0xD9, 0xF1, // 设置预充电周期
0xDB, 0x40, // 设置 VCOMH 电平
0xA4, // 禁用全局显示
0xA6, // 设置正常显示模式(非反色)
0xAF // 打开显示
};
void Oled_Init(){
HAL_Delay(200);
// Initial Setting
uint8_t i;
for(i=0; i< (sizeof(Init_Settings)/sizeof(Init_Settings[0])); i++){
HAL_I2C_Mem_Write(&hi2c1 ,0x78,0x00,I2C_MEMADD_SIZE_8BIT,Init_Settings + i,1,0x100);
}
}
- 清屏
初始化显示后,完成清屏
void Oled_Clear(){
uint8_t i,n;
for(i=0;i<8;i++)
{
Oled_Write_CMD(0xb0+i);
Oled_Write_CMD (0x00);
Oled_Write_CMD (0x10);
for(n=0;n<128;n++)
Oled_Write_Data(0);
}
}
- 写位置和写字符
void Oled_Set_Pos(uint8_t x, uint8_t y)
{
Oled_Write_CMD(0xb0+y);
Oled_Write_CMD(((x&0xf0)>>4)|0x10);
Oled_Write_CMD(x&0x0f);
}
// x ~ [0~127], y ~ [0, 64]
void Oled_Show_Char(uint8_t x,uint8_t y,uint8_t chr,uint8_t Char_Size)
{
unsigned char c=0,i=0;
c