STM32开发常见问题解析与知识汇总
在STM32开发过程中,我们会遇到各种各样的问题,下面将对一些常见问题进行详细解析。
任务添加对闪烁速率的影响
在
main.c
文件中添加任务2,该任务仅在循环中执行
__asm__("nop")
。需要在
main()
函数里启动调度器之前创建此任务。当添加这个任务后,闪烁速率会显著变慢。这是因为第二个任务占用了CPU时间,使得第一个任务能使用的CPU时间减少。
USART相关知识
- 空闲状态TTL电平 :USART信号的空闲状态TTL电平为高(接近5伏)。
- 数据字节序 :USART数据采用小端字节序,即最低有效位在前。
-
时钟启用
:使用UART时,必须启用
RCC_GPIOx和RCC_USARTn时钟。 - 8N1含义 :“8N1”表示8位数据、无校验位和1位停止位。
- 数据发送问题 :如果在设备未清空时提供UART数据进行发送,数据将会丢失。
-
任务创建时机
:任务可以在
vTaskStartScheduler()之前和之后创建。
USB相关知识
-
GPIO准备
:在启用USB外设之前,必须启用
GPIOA时钟,之后USB外设会自动接管PA11和PA12。 -
GPIO配置
:USB没有备用的GPIO配置,仅使用
PA11和PA12。 -
事件处理函数
:必须经常调用
usbd_poll()函数来处理需要操作的USB事件。
SPI相关知识
| 项目 | 详情 |
|---|---|
| 双向链路数据线路 |
SPI双向链路使用两条数据线路:
MOSI
和
MISO
。
|
| 时钟来源 |
时钟(
SCK
)始终由SPI总线的主设备提供。
|
| 电压电平 | 根据系统设计要求,SPI信号通常使用5伏或3.3伏的电压电平,STM32设备使用3.3伏。 |
| 上拉电阻原因 |
由于STM32 MCU将
/NSS
输出配置为开漏输出,无论初始配置如何,都必须使用上拉电阻,否则选择线永远不会变高。
|
| 发送虚拟值原因 | 在某些SPI事务中,发送虚拟值是为了使主外设发出从设备发送数据所需的时钟脉冲,因为从设备总是依赖SPI主设备提供时钟。 |
内存和代码相关知识
-
结构体成员类型
:在
typedef为s_overlay的结构体中,成员定义为字符指针而非长整型,是因为计算字节大小时需要字符指针。如果类型为长整型,计算出的大小将以字为单位,而非字节。 -
xflash内存区域
:在链接脚本中添加
xflash内存区域,是为了存储所有W25QXX闪存代码,这些代码不会出现在MCU的闪存中。并且该代码从地址零开始加载到xflash中,而MCU闪存从0x08000000开始。 - 覆盖存根函数用途 :覆盖存根函数调用覆盖管理器,确保所需代码加载到SRAM的覆盖区域。一旦知道函数指针,就必须传递调用参数和返回值(如果有)。
-
GNU声明
noinline用途 :__attribute__((noinline, section(".ov_fee")))中的noinline属性可防止编译器将函数视为“内联”代码,这对于编译器可能优化的小函数尤为重要。 -
声明位置
:
__attribute__((section("…"))声明只能出现在函数原型中。
RTC相关知识
- 中断事件 :RTC可能产生三种中断事件,分别是RTC(滴答)、闹钟和溢出。
-
临界操作函数
:
taskENTER_CRITICAL_FROM_ISR()和taskEXIT_CRITICAL_FROM_ISR()函数用于在执行关键操作时阻止其他中断发生。 - 计数器宽度 :RTC计数器为32位宽。
-
时钟源
:当STM32断电时,LSE时钟(32.768 kHz晶体振荡器)会继续工作,前提是电池电压
VBAT供应正常。 - 最精确时钟源 :最精确的时钟源是HSE时钟,因为它由8 MHz晶体振荡器控制,但仅在供电正常时有效。
I2C相关知识
-
读取字节值
:从十六进制从地址
$21读取数据时,发送的字节值为$43。因为十六进制地址$21左移1位后为$42,读操作需要在最低有效位设置为1。 -
NAK接收
:当主设备向总线上不存在的从设备请求响应时,由于从设备要确认响应需将
SDA线拉低,若没有从设备响应,上拉电阻会使该线保持高电平,从而默认接收到NAK。 -
/INT线优势
:PCF8574的
/INT线允许从设备在输入线状态改变时直接通知控制MCU,否则MCU需要通过I2C总线进行读请求来检测线状态的变化。 - 准双向含义 :在PCF8574中,准双向意味着为了接收输入信号,GPIO端口需要设置为弱高电平,以便输入驱动器可以将其拉低,这样它既可以作为输入端口也可以作为输出端口。但如果GPIO端口设置为低电平,则不能用于输入。
- 电流源和吸收区别 :电流源是指电流受控制,从正极通过连接到地(负极)的负载流动;而电流吸收是指负载连接到正电源,电流在接地端进行开关控制。
AFIO和OLED相关知识
-
输出引脚配置
:对于AFIO输出引脚,必须使用
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL或GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN宏,否则引脚将与外设断开连接,表现为普通GPIO。 -
时钟启用
:进行AFIO更改时,必须通过
rcc_periph_clock_enable()启用RCC_AFIO时钟。 - 输入引脚配置 :输入引脚除了需要启用AFIO外设时钟和GPIO时钟,并初始化外设输入外,无需特殊处理。
-
OLED D/C输入用途
:OLED的
D/C输入线用于区分OLED命令字节(低电平时)和OLED图形数据(高电平时)。
DMA相关知识
在演示程序中,启动下一次DMA传输前,需要在禁用DMA通道后更改起始地址和长度。每个DMA通道都有自己的ISR例程。在像演示程序那样的内存到外设传输中,DMA请求来自外设(内存到内存传输除外),在演示程序里,SPI发送缓冲区空标志会触发传输请求。使用SPI的演示程序中,DMA传输开始需要满足以下三个条件:
1. 启用DMA通道。
2. 启用SPI的DMA TX功能。
3. 启用SPI。
graph TD;
A[开始] --> B[启用DMA通道];
B --> C[启用SPI的DMA TX功能];
C --> D[启用SPI];
D --> E[DMA传输开始];
ADC相关知识
- 温度表示 :STM32内部温度以电压形式表示。
-
配置差异
:
GPIO_CNF_INPUT_ANALOG与GPIO_CNF_INPUT_PULL_UPDOWN或GPIO_CNF_INPUT_FLOAT的区别在于,前者允许变化的电压到达ADC输入,否则只能检测到低或高信号。 - 时钟速率计算 :如果PCLK频率为36 MHz,配置预分频除数为4时,ADC时钟速率为36 MHz ÷ 4 = 9 MHz。
-
功耗影响因素
:影响ADC总功耗的三个配置选项为:
adc_power_on(adc)(和off)、adc_enable_temperature_sensor()(和disable)、adc_start_conversion_direct(adc)。 -
采样时间计算
:假设预分频后的ADC时钟为12 MHz,配置为
ADC_SMPR_SMP_41DOT5CYC的采样时间为(41.5 + 12.5) ÷ 12 MHz = 54 ÷ 12e6 = 4.5 μs。
时钟相关知识
| 时钟类型 | 优点 | 缺点 |
|---|---|---|
| RC时钟 | 不需要外部晶体(晶体太大,无法集成在IC上)。 | 容易出现漂移和抖动,稳定性较差,精度较低,会导致生成波特率等方面出现问题。 |
| 晶体衍生时钟 | 稳定,能与外部硬件匹配,更适合生成波特率等。 | 无 |
- PLL用途 :PLL用于将时钟频率倍频到高于其输入时钟的速率。
- AHB含义 :AHB代表AMBA高性能总线。
-
GPIO PA8配置原因
:必须将GPIO PA8配置为
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL,否则没有ALTFN的宏名将使GPIO保持断开连接,只是一个普通的GPIO,与MCO输出无关。
RC Servo和定时器相关知识
- 信号周期 :RC Servo信号的周期是指脉冲开始到下一个脉冲开始的时间。
- 定时器输入频率 :在Blue Pill STM32F103C8T6上,定时器输入时钟频率为72 MHz,而不是36 MHz,因为当AHB1预分频器不为1时,定时器频率是AHB1总线频率的两倍。
- 脉冲宽度改变 :改变定时器的输出比较寄存器的值可以改变脉冲宽度。
定时器输入相关知识
- 数字滤波器用途 :定时器输入的数字滤波器用于消除随机噪声脉冲引起的误触发。
- PWM输入模式复位 :在如演示中配置的PWM输入模式下,计数器在捕获1事件发生后复位。
- IC2输入信号来源 :在PWM输入模式下,IC2输入信号来自输入通道1。
CAN相关知识
STM32F103 CAN外设支持两个FIFO(FIFO 0和FIFO 1)和两个滤波器组(组0和组1)。当需要提供一对滤波器但只需要一个时,可以采用以下两种方法:
- 声明两个相同的滤波器(只有一个会触发)。
- 声明一个有效滤波器和一个不可能的滤波器。
RTR(远程传输请求)标志在以隐性状态发送时用于请求传输,回复时RTR标志总是以显性状态发送。
中断和队列相关知识
- 接收中断处理作用 :接收中断处理通过在寄存器被覆盖之前将外设数据寄存器中的数据存储到内存中,从而更及时地读取数据,有助于防止数据丢失。
- FreeRTOS队列优势 :使用FreeRTOS队列而不是内存数组缓冲区,是因为它提供了经过严格测试的代码,使用最小的临界区使操作具有原子性,将数据保存到内存中。
- ISR不阻塞原因 :ISR不能阻塞执行,以避免阻塞其他中断,立即返回可以使被中断的代码继续执行。
-
函数选择原因
:必须使用
libopencm3的usart_send()函数而不是usart_send_blocking(),因为usart_send_blocking()不知道它与FreeRTOS内核一起使用,会一直占用CPU周期,直到USART可以接受数据,这会导致CPU被占用,直到发生抢占。当设备未准备好时,调用taskYIELD()更合适。 -
调用前提条件
:调用
usart_send()之前,调用者必须测试设备是否准备好,因为该函数假定设备已准备好。
Makefile和FreeRTOS相关知识
-
BINARY宏定义
:
make宏BINARY定义了带有.elf后缀的应用程序可执行文件的名称。 -
头文件用途
:
FreeRTOSConfig.h头文件用于配置FreeRTOS系统的多个方面。 -
编译器选项添加
:要仅为
speedy.c模块的编译添加编译器选项-O3,可以在Makefile中添加规则:speedy.o: CFLAGS += -O3。 -
heap_1缺点
:在FreeRTOS项目中使用
heap_1.c的主要缺点是不支持free()函数,无法释放和重用动态分配的内存。
STM32F103C8T6 GPIO引脚信息
| 引脚名称 | 类型 | I/O 电平 | 复位后默认 | 重映射 |
|---|---|---|---|---|
| VBAT | S | - | VBAT | - |
| PC13-TAMPER-RTC | I/O | - | PC13 | TAMPER-RTC |
| PC14-OSC32_IN | I/O | - | PC14 | OSC32-IN |
| PC15-OSC32_OUT | I/O | - | PC15 | OSC32-OUT |
| OSC_IN | I | - | OSC_IN | PD0 |
| OSC_OUT | O | - | OSC_OUT | PD1 |
| NRST | I/O | - | NRST | - |
| VSSA | S | - | VSSA | - |
| VDDA | S | - | VDDA | - |
| PA0-WKUP | I/O | - | PA0 | WKUP, USART2_CTS, ADC12_IN0, TIM2_CH1_ETR |
| PA1 | I/O | - | PA1 | USART2_RTS, ADC12_IN1, TIM2_CH2 |
| PA2 | I/O | - | PA2 | USART2_TX, ADC12_IN2, TIM2_CH3 |
| PA3 | I/O | - | PA3 | USART2_RX, ADC12_IN3, TIM2_CH4 |
| PA4 | I/O | - | PA4 | SPI1_NSS, USART2_CK, ADC12_IN4 |
| PA5 | I/O | - | PA5 | SPI1_SCK, ADC12_IN5 |
| PA6 | I/O | - | PA6 | SPI1_MISO, TIM1_BKIN, ADC12_IN6, TIM3_CH1 |
| PA7 | I/O | - | PA7 | SPI1_MOSI, TIM1_CH1N, ADC12_IN7, TIM3_CH2 |
| PB0 | I/O | - | PB0 | ADC12_IN8, TIM1_CH2N, TIM3_CH3 |
| PB1 | I/O | - | PB1 | ADC12_IN9, TIM1_CH3N, TIM3_CH4 |
| PB2 | I/O | FT | PB2/BOOT1 | - |
| PB10 | I/O | FT | PB10 | I2C2_SCL, TIM2_CH3, USART3_TX |
| PB11 | I/O | FT | PB11 | I2C2_SDA, TIM2_CH, USART3_RX |
| VSS_1 | S | - | VSS_1 | - |
| VDD_1 | S | - | VDD_1 | - |
| PB12 | I/O | FT | PB12 | SPI2_NSS, I2C2_SMBAl, USART3_CK, TIM1_BKIN |
| PB13 | I/O | FT | PB13 | SPI2_SCK, USART3_CTS, TIM1_CH1N |
| PB14 | I/O | FT | PB14 | SPI2_MISO, USART3_RTS, TIM1_CH2N |
| PB15 | I/O | FT | PB15 | SPI2_MOSI, TIM1_CH3N |
| PA8 | I/O | FT | PA8 | USART1_CK, TIM1_CH1, MCO |
| PA9 | I/O | FT | PA9 | USART1_TX, TIM1_CH2 |
| PA10 | I/O | FT | PA10 | USART1_RX, TIM1_CH3 |
| PA11 | I/O | FT | PA11 | USART1_CTS, CANRX, USBDM, TIM1_CH4 |
| PA12 | I/O | FT | PA12 | USART1_RTS, CANTX, USBDP, TIM1_ETR |
| PA13 | I/O | FT | JTMS/SWDIO | PA13 |
| VSS_2 | S | - | VSS_2 | - |
| VDD_2 | S | - | VDD_2 | - |
| PA14 | I/O | FT | JTCK/SWCLK | PA14 |
| PA15 | I/O | FT | JTDI | TIM2_CH1_ETR, PA15, SPI1_NSS |
| PB3 | I/O | FT | JTDO | TIM2_CH2, PB3, TRACESWO, SPI1_SCK |
| PB4 | I/O | FT | JNTRST | TIM3_CH1, PB4, SPI1_MISO |
| PB5 | I/O | FT | PB5 | I2C1_SMBAI, TIM3_CH2, SPI1_MOSI |
| PB6 | I/O | FT | PB6 | I2C1_SCL, USART1_TX, TIM4_CH1 |
| PB7 | I/O | FT | PB7 | I2C1_SDA, USART1_RX, TIM4_CH2 |
| BOOT0 | I | - | BOOT0 | - |
| PB8 | I/O | FT | PB8 | TIM4_CH3, I2C1_SCL, CANRX |
| PB9 | I/O | FT | PB9 | TIM4_CH4, I2C1_SDA, CANTX |
| VSS_3 | S | - | VSS_3 | - |
| VDD_3 | S | - | VDD_3 | - |
符号说明:
-
I
:输入
-
O
:输出
-
S
:电源
-
FT
:5伏耐受
以上内容涵盖了STM32开发中多个方面的常见问题及相关知识,希望对大家的开发工作有所帮助。
STM32开发常见问题解析与知识汇总
在STM32开发中,掌握各种外设和功能的使用细节至关重要。上半部分已经介绍了许多常见问题和相关知识,接下来将继续深入探讨一些关键技术点。
任务与调度相关知识进一步探讨
在任务调度方面,当在
main.c
文件中添加任务时,除了要考虑任务对CPU时间的占用影响闪烁速率外,还需要注意任务的优先级设置。不同优先级的任务在调度器的管理下,执行顺序和时间分配会有所不同。高优先级任务会优先获得CPU资源,而低优先级任务可能需要等待高优先级任务执行完毕或者被阻塞时才有机会执行。
例如,若将任务2的优先级设置得比任务1高,那么任务2会更频繁地占用CPU时间,可能会导致任务1的执行间隔变得更长,闪烁速率会进一步变慢。反之,如果任务2的优先级低于任务1,任务1会优先执行,任务2可能会在任务1空闲时才执行,对闪烁速率的影响相对较小。
通信协议相关知识拓展
在USART通信中,除了了解其空闲状态TTL电平、数据字节序、时钟启用等基本信息外,还需要关注波特率的设置。波特率决定了数据传输的速率,不同的应用场景可能需要不同的波特率。在设置波特率时,需要根据硬件特性和通信需求进行合理选择。
在SPI通信中,除了之前提到的数据线路、时钟来源、电压电平、上拉电阻和发送虚拟值等内容,还需要注意SPI模式的选择。SPI有四种模式(模式0 - 模式3),不同的模式由时钟极性(CPOL)和时钟相位(CPHA)的不同组合决定。不同的设备可能支持不同的SPI模式,因此在连接SPI设备时,需要确保主设备和从设备的SPI模式一致,否则可能会导致通信错误。
存储与内存管理相关知识深入解析
在内存和代码相关知识中,对于
xflash
内存区域的使用,还需要注意内存的分配和释放。虽然
xflash
用于存储特定的闪存代码,但在实际应用中,可能需要动态地分配和使用这块内存。在进行内存分配时,需要确保不会超出
xflash
的可用空间,避免出现内存溢出的问题。
对于覆盖存根函数,它在代码加载和执行过程中起着重要的桥梁作用。在调用覆盖存根函数时,需要确保传递正确的参数,以便覆盖管理器能够准确地加载所需的代码到SRAM的覆盖区域。同时,还需要处理好函数返回值的传递,确保程序的正常运行。
定时器与时钟相关知识补充
在定时器相关知识中,除了了解定时器输入时钟频率、脉冲宽度改变和数字滤波器等内容外,还需要关注定时器的计数模式。定时器有向上计数、向下计数和中央对齐计数等多种模式。不同的计数模式适用于不同的应用场景,例如,向上计数模式常用于定时任务,而中央对齐计数模式常用于PWM信号的生成。
在时钟相关知识中,对于PLL的使用,需要注意其倍频系数的设置。不同的倍频系数会导致输出时钟频率的不同,需要根据系统的需求进行合理选择。同时,还需要考虑PLL的稳定性和启动时间,确保系统能够稳定地运行。
中断与队列相关知识的实际应用
在中断和队列相关知识中,接收中断处理和FreeRTOS队列的使用在实际应用中非常重要。在使用接收中断处理时,需要确保中断服务程序(ISR)的执行时间尽可能短,避免阻塞其他中断。可以采用以下步骤来优化ISR的执行:
1. 在ISR中只进行必要的操作,例如标记数据的接收状态。
2. 将复杂的处理任务放到任务中进行,通过FreeRTOS队列将数据传递给任务。
在使用FreeRTOS队列时,需要注意队列的长度和数据类型的匹配。队列的长度需要根据实际的数据量进行合理设置,避免队列溢出。同时,队列中存储的数据类型需要与发送和接收函数的参数类型一致,否则可能会导致数据传输错误。
开发工具与配置相关知识总结
在Makefile和FreeRTOS相关知识中,
make
宏
BINARY
的定义和
FreeRTOSConfig.h
头文件的配置对于项目的构建和运行非常重要。在修改
BINARY
宏时,需要确保定义的名称符合项目的命名规范,并且在编译和链接过程中不会出现冲突。
对于
FreeRTOSConfig.h
头文件的配置,需要根据项目的需求进行合理调整。该头文件中包含了许多重要的配置选项,例如任务优先级、堆栈大小、内存分配策略等。不同的配置选项会影响FreeRTOS的性能和功能,需要仔细考虑每个选项的含义和作用。
总结
通过以上对STM32开发中多个方面的知识深入探讨和拓展,我们可以更全面地了解STM32的各种功能和应用。在实际开发过程中,需要根据具体的需求和场景,灵活运用这些知识,解决遇到的各种问题。同时,还需要不断学习和积累经验,提高自己的开发能力。
以下是一个简单的流程图,展示了在STM32开发中遇到问题时的解决思路:
graph TD;
A[遇到问题] --> B[分析问题类型];
B --> C{是否为硬件问题};
C -- 是 --> D[检查硬件连接和电源];
C -- 否 --> E{是否为软件问题};
E -- 是 --> F[检查代码逻辑和配置];
F --> G{是否与通信协议有关};
G -- 是 --> H[检查通信参数和协议模式];
G -- 否 --> I{是否与内存管理有关};
I -- 是 --> J[检查内存分配和释放];
I -- 否 --> K[其他软件问题排查];
D --> L[解决硬件问题];
H --> M[解决通信协议问题];
J --> N[解决内存管理问题];
K --> O[解决其他软件问题];
L --> P[测试系统];
M --> P;
N --> P;
O --> P;
P --> Q{问题是否解决};
Q -- 是 --> R[完成开发];
Q -- 否 --> A;
在实际开发中,遇到问题是很正常的,关键是要掌握正确的解决方法和思路。通过不断地实践和总结,我们可以更好地应对各种挑战,提高STM32开发的效率和质量。
希望以上内容对大家在STM32开发过程中有所帮助,祝大家开发顺利!
超级会员免费看
1792

被折叠的 条评论
为什么被折叠?



