输入输出模式解析
输出模式
在输出模式下,通常不需要设置上下拉电阻.
输出电平由
LL_GPIO_SetOutputPin
和LL_GPIO_ResetOutputPin
函数直接控制。
输入模式
在输入模式下,设置上下拉电阻是非常重要的.
输入引脚悬空时可能会导致不确定的电平,从而引起误触发或噪声。
初始设置相关资料
- 引脚模式:输入、输出、复用功能等。
LL_GPIO_SetPinMode(GPIOC, LL_GPIO_PIN_13, LL_GPIO_MODE_INPUT); //输入
LL_GPIO_SetPinMode(GPIOC, LL_GPIO_PIN_13, LL_GPIO_MODE_OUTPUT);//输出
LL_GPIO_SetPinMode(GPIOC, LL_GPIO_PIN_13, LL_GPIO_MODE_ALTERNATE);//复用
1. 复用功能(Alternate Function)
复用功能允许GPIO引脚用于外设的功能,例如USART、SPI、I2C等。每个GPIO引脚可以配置为多种复用功能之一。
假设我们要将GPIOA第9引脚配置为USART1的TX引脚:
// 使能GPIOA时钟
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOA);
// 配置GPIOA第9引脚为复用功能模式
LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_9, LL_GPIO_MODE_ALTERNATE);
// 设置引脚速度为高速
LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_9, LL_GPIO_SPEED_FREQ_HIGH);
// 设置引脚输出类型为推挽输出
LL_GPIO_SetPinOutputType(GPIOA, LL_GPIO_PIN_9, LL_GPIO_OUTPUT_PUSHPULL);
// 设置引脚上拉/下拉电阻为无
LL_GPIO_SetPinPull(GPIOA, LL_GPIO_PIN_9, LL_GPIO_PULL_NO);
- 输出类型:推挽、开漏等。
LL_GPIO_SetPinOutputType(GPIOC, LL_GPIO_PIN_13, LL_GPIO_OUTPUT_PUSHPULL); //推挽
LL_GPIO_SetPinOutputType(GPIOC, LL_GPIO_PIN_13, LL_GPIO_OUTPUT_OPENDRAIN);//开漏
推挽输出(Push-Pull)
- 特点:引脚可以输出高电平和低电平。
- 用途:适用于大多数通用输出场景。
开漏输出(Open-Drain)
- 特点:引脚只能输出低电平,高电平需要外部上拉电阻。
- 用途:适用于需要外部上拉电阻的场景,如I2C通信。
- 速度:低速、中速、高速、非常高速等。
LL_GPIO_SetPinSpeed(GPIOC, LL_GPIO_PIN_13, LL_GPIO_SPEED_FREQ_LOW);//低
LL_GPIO_SetPinSpeed(GPIOC, LL_GPIO_PIN_13, LL_GPIO_SPEED_FREQ_MEDIUM);//中
LL_GPIO_SetPinSpeed(GPIOC, LL_GPIO_PIN_13, LL_GPIO_SPEED_FREQ_HIGH);//高
LL_GPIO_SetPinSpeed(GPIOC, LL_GPIO_PIN_13, LL_GPIO_SPEED_FREQ_VERY_HIGH);//非常高
速度解析
低速(Low Speed)
- 特点:最低的输出速度,适用于低频信号。
- 用途:适用于对速度要求不高的场景。
中速(Medium Speed)
- 特点:中等的输出速度。
- 用途:适用于一般的输出场景。
高速(High Speed)
- 特点:较高的输出速度。
- 用途:适用于对速度有一定要求的场景。
非常高速(Very High Speed)
- 特点:最高的输出速度。
- 用途:适用于对速度要求很高的场景。
- 上下拉电阻:上拉、下拉、无等。
LL_GPIO_SetPinPull(GPIOC, LL_GPIO_PIN_13, LL_GPIO_PULL_UP);//上拉
LL_GPIO_SetPinPull(GPIOC, LL_GPIO_PIN_13, LL_GPIO_PULL_DOWN);//下拉
LL_GPIO_SetPinPull(GPIOC, LL_GPIO_PIN_13, LL_GPIO_PULL_NO);//无上下拉 可忽略
中断和事件:配置中断和事件触发条件
// 使能GPIOC时钟
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOC);// 配置GPIOC第13引脚为输入模式
LL_GPIO_SetPinMode(GPIOC, LL_GPIO_PIN_13, LL_GPIO_MODE_INPUT);// 设置上拉电阻
LL_GPIO_SetPinPull(GPIOC, LL_GPIO_PIN_13, LL_GPIO_PULL_UP);// 使能外部中断线
LL_EXTI_EnableIT_0_31(LL_EXTI_LINE_13);// 选择GPIOC第13引脚作为外部中断源
LL_SYSCFG_SetEXTISource(LL_SYSCFG_EXTI_PORTC, LL_SYSCFG_EXTI_LINE13);// 使能NVIC中断
NVIC_EnableIRQ(EXTI15_10_IRQn);// 设置中断优先级
NVIC_SetPriority(EXTI15_10_IRQn, 1);// 中断服务例程
void EXTI15_10_IRQHandler(void) {
if (LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_13) != RESET) {
// 清除中断标志
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_13);// 处理中断 // ... }
}
驱动i2c屏幕
可能是有什么问题没有调试通代码放在这里坐等有人解答!
#include <stm32f1xx_hal.h>
#include <stm32f1xx_hal_gpio.h>
#include <stm32f1xx_hal_spi.h>
#include <stm32f1xx_hal_rcc.h>
SPI_HandleTypeDef hspi1; // SPI句柄
const char *s;
// 初始化序列
// 初始化序列
uint8_t init_sequence[] = {
0xAE, // 关闭 OLED 显示面板
0x15, 0x00, 0x7F, // 设置列地址范围,起始值为 0,结束值为 127
0x75, 0x00, 0x7F, // 设置行地址范围,起始值为 0,结束值为 127
0x81, 0x80, // 设置对比度控制,对比度值为 128
0xA0, 0x51, // 段重映射,设置段重映射方式
0xA1, 0x00, // 设置显示起始行,起始行地址为 0
0xA2, 0x00, // 设置显示偏移,偏移值为 0
0xA4, // 设置正常显示模式
0xA8, 0x7F, // 设置多路复用比率,多路复用比率为 127
0xB1, 0xF1, // 设置相位长度
0xB3, 0x00, // 设置 DCLK,设置 DCLK 为 100 Hz
0xAB, 0x01, // 启动内部振荡器
0xB6, 0x0F, // 设置相位长度
0xBE, 0x0F, // 设置 VCOMH 电压
0xBC, 0x08, // 设置预充电周期
0xD5, 0x62, // 设置显示时钟分频
0xFD, 0x12, // 设置命令锁存
0xA0, 0x51, // 再次设置扫描方式,设置扫描方式从左往右,从上到下
0xAF, // 打开 OLED 显示面板
};
void spiinit()
{
// 第一步开启时钟
__HAL_RCC_SPI1_CLK_ENABLE(); // SPI1
__HAL_RCC_GPIOA_CLK_ENABLE(); // PA
// 第二步设置引脚
GPIO_InitTypeDef GPIO_InitStructure; // GPIO初始化结构体
// MOSI
GPIO_InitStructure.Pin = GPIO_PIN_5;
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
// MISO
GPIO_InitStructure.Pin = GPIO_PIN_6;
GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
// NSS
GPIO_InitStructure.Pin = GPIO_PIN_4;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_PULLDOWN;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
// 第三步设置SPI
hspi1.Instance = SPI1; // SPI1
hspi1.Init.Direction = SPI_DIRECTION_2LINES; // 双线模式
hspi1.Init.Mode = SPI_MODE_MASTER; // 主机模式
hspi1.Init.DataSize = SPI_DATASIZE_8BIT; // 8位
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; // 低电平
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; // 上升沿
hspi1.Init.NSS = SPI_NSS_SOFT; // 软件片选
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; // 100MHz
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; // 高位在前
hspi1.Init.TIMode = SPI_TIMODE_DISABLE; // 硬件模式
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; // CRC校验
hspi1.Init.CRCPolynomial = 7; // CRC校验
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
// 初始化失败处理
while (1)
;
}
__HAL_SPI_ENABLE(&hspi1); // 使能SPI
}
void spi_select()
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); // 选择从设备
}
void spi_deselect()
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); // 取消选择从设备
}
uint8_t spi_write(uint8_t data)
{
uint8_t rdata;
HAL_SPI_Transmit(&hspi1, &data, 1, 1000);
return rdata;
}
int main()
{
spiinit(); // 初始化
s = "hello world";
// 发送初始化序列
for (int i = 0; i < sizeof(init_sequence) / sizeof(init_sequence[0]); i++)
{
spi_select();
spi_write(init_sequence[i]);
HAL_Delay(10);
spi_deselect();
HAL_Delay(10);
}
while (*s)
{
spi_deselect();
HAL_Delay(10);
spi_write(*s);
s++;
spi_select();
HAL_Delay(10);
}
while (1)
;
}