STM32使用过程中的踩坑记录

发布者:reaper2009最新更新时间:2022-08-09 来源: csdn关键字:STM32  使用过程  踩坑记录 手机看文章 扫描二维码
随时随地手机看文章

1. 中断函数不要随意使用prinf()函数

记调试步进电机加速减速过程的一次大坑。


2. 使用HAL库的时候不要在中断中使用HAL_Delay()函数

HAL库的HAL_Delay()函数是通过Systick定时器的1ms中断实现的,一般情况下Systick定时器的优先级设置为最低,因此在更高优先级的中断触发后导致HAL_Delay()函数uwtick值无法更新,因此程序会卡死在HAL_Delay()函数中。


3.注意STM32库在配置串口字长时是包含校验位的字长,而一般上位机配置的串口字长是不包含校验位的。

这点在配置使用校验时是非常重要的,如果配置出错会导致通讯不正常。


4.使用不同的开发板的时候一定要注意不同板子上的晶振可能是不一样的

之前用的板子是8M的晶振,配置好了可以正常使用。后面换了板子是25M晶振的。只修改了SystemClock_Config()函数中的因子,忘记修改晶振配置的值,导致时钟频率一直不对。晶振不同时,一定要到stm32xxxx_hal_conf.h中修改HSE_VALUE为相应的晶振值


5.移植FreeRTOS,让stm32hal和freeRTOS共用SYSTICK,程序全速运行会卡死在hardfault中断,但单步调试可以运行过去

在之前的板子上可以运行,但在后面新作的板子上出现了这个问题。(这一点感觉好奇怪)

systick中断代码:


void SysTick_Handler(void)

{

 HAL_IncTick();

 #if (INCLUDE_xTaskGetSchedulerState == 1 )

  if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {

 #endif /* INCLUDE_xTaskGetSchedulerState */

  xPortSysTickHandler();

 #if (INCLUDE_xTaskGetSchedulerState == 1 )

  }

 #endif /* INCLUDE_xTaskGetSchedulerState */

}


在stm32f4xx_it.c文件中一定要包含FreeRTOS.h头文件,否则会导致上述函数中条件编译的宏不会生效,导致在还没开启任务调度时,触发SysTick中断后会直接进入xPortSysTickHandler()函数,导致触发了hardfault中断。


6. STM32F429使用TIM2和TIM5的的注意事项

TIM2和TIM5是32位定时器,TIM2和TIM5产生PWM并通过DMA传输时必须按32位传输(即DMA设置的长度位32位)且用于为输出比较寄存器赋值的数组也必须为32为的(在使用TIM2和定时器5驱动WS2812时一定要注意)。

注:移植之前的ws21812灯珠驱动程序(之前用的是TIM3属于16位寄存器),改到TIM2来驱动用逻辑分析仪一直没有测到输出波形,又测试了TIM5也是这样还以为TIM2和TIM5的PWM不能够通过DMA传输呢!这个事情告诉我们一定要认真读手册

7. STM32F429不能够通过PA1和PA2输出PWM

https://blog.csdn.net/xiaoyuanwuhui/article/details/109597401中有记录


8. STM32的部分外设在初始化初始化函数只能执行1次!!!

在使用STM32ADC外设时,红外测距模块和电流采样模块都用到了ADC,因而在两个模块分别初始化的时候调用了两次ADC初始化的函数bsp_adc1Init(),导致电流检测数据不正常(实际硬件测量没有电压,但ADC的采样值却有500多的值(实际应该在10左右))。在屏蔽掉红外测距模块的初始化函数后,数据便恢复正常了。

解决方法:仿照crazyfile代码中硬件外设初始化的方法,定义一个isInit的变量用于指示当前外设初始化函数是否执行过,如果执行过则直接跳出。


static bool isInit = false;


void bsp_adc1Init(void) {

if(isInit) {

return;

}

/* init adc module */

//...

isInit = ture;


采用上述方式,可以防止adc外设被重复初始化,因此可以避免上面出现的问题,又可以很好的保证红外测距模块和电流采样模块的独立性和完整性。


9. STM32的PWM控制开启和停止的函数在FREERTOS环境下使用时可能需要进入临界段保护

在实际的一个项目中用到了步进电机控制,在执行任务的过程中可能会不断地启停步进电机控制,而且步进电机的启动和停止控制不是在一个任务中实现的,这会导致步进电机出现丢步,从而导致电机有异响.(实际从示波器中确实可以看到约1ms的波形中断).

HAL_TIM_PWM_Start()和HAL_TIM_PWM_Stop()函数用于步进电机的启停控制.

实测发现:将上述两个函数放到taskEnter_CRITICAL()和taskEXIT_CRITICAL()之间便不会再出现上面电机异响的现象了.


10.通过cubeMX配置ADC+DMA功能时可能出现功能不正常的问题

开始先通过cubeMX配置生成了一个ADC功能测试的例程,后面为了测试ADC+DMA功能,在该工程中又增加了DMA配置,但通过该工程生成的代码就是有问题,ADC不能正确转换并更新到变量中。经排查发现是生成的代码中ADC初始化函数MX_ADC_Init()在DMA初始化函数MX_DMA_Init()之前导致的,将两个初始化函数调整下顺序功能便正常了。

分析:MX_DMA_Init()函数中主要是开启DMA时钟,MX_ADC_Init()函数中进行了DMA相关的配置,可能是由于配置DMA之前未打开DMA时钟导致的。

初始化函数的前后顺序可按照下图进行调序:

在这里插入图片描述

11.HAL_ADCEx_InjectedStop_IT(&hadc1)函数使用注意事项

在默认配置ADC规则通道DMA采样+外部触发注入模式后,并开启了外部触发注入转换和规则通道DMA转换,中间过程中想校准注入通道对应的初始值,需要将外部触发改为软件触发并采样取平均值。在修改配置之前首先要将规则通道和注入通道转换全部关闭且一定要先关闭规则通道转换再关闭注入通道转换之后再修改相应的配置。


正确顺序:


HAL_ADC_Stop_DMA(&hadc1); //

HAL_ADCEx_InjectedStop_IT(&hadc1); //关闭注入组之前必须先把规则组关闭


HAL_ADCEx_InjectedStop_IT(&hadc1);函数中有如下的注释,说明了在没有规则组转换要继续时才会关闭,上面配置的是规则组通过DMA转换,会一直转换,所以要先把规则组DMA先关闭。


/* Stop potential conversion and disable ADC peripheral                     */

/* Conditioned to:                                                          */

/* - No conversion on the other group (regular group) is intended to        */

/*   continue (injected and regular groups stop conversion and ADC disable  */

/*   are common)                                                            */

/* - In case of auto-injection mode, HAL_ADC_Stop must be used.             */ 

//翻译如下:

/* 停止电位转换并禁用 ADC 外设

  适应于:

  - 其他组(常规组)上没有转换打算继续(注入和常规组停止转换和 ADC 禁用很常见)

  - 在自动注入模式的情况下,必须使用 HAL_ADC_Stop。 */


12 记一次串口无法进入IDLE中断的问题

为某项目新作了一块板子,在移植程序的时候发现,总是无法进入串口IDLE的接收中断,换到其他串口便能够正常进入中断。经过排查最终发现是bootloader程序中也配置过串口2,但两次映射的串口2引脚不一致导致的。将boot程序中的串口2的引脚映射改为和app程序中一样的引脚映射便没有了该问题。


13 记一次粗心导致CAN通讯异常的问题

在调试新板子,只要插着驱动器的CAN通讯线,必会导致程序卡死在CAN中断中(之气前还一直认为板子程序没有跑起来,调试发现是程序一直在触发CAN中断)。调试了好长时间,中间还以为是配置双CAN通信的问题,可屏蔽掉还是不行,最终发现是开启了CAN错误中断,当时为了调试CAN2方便,将错误中断中处理的can1重新初始化函数屏蔽了,而这之前又执行了__HAL_CAN_RESET_HANDLE_STATE(&hcan1)将hcan1的State状态置为了HAL_CAN_STATE_RESET,导致一直触发CAN_FLAG_ERRI,便卡在了CAN中断函数中

导致出现问题的代码如下:


void HAL_CAN_ErrorCallback(CAN_HandleTypeDef *hcan) {

  if(hcan->Instance == CAN1) {

    /* 记录CAN错误信息 */

    /* 处理CAN报错 */

    if(HAL_CAN_GetError(&hcan1) != HAL_CAN_ERROR_NONE) {

      HAL_CAN_ResetError(&hcan1);

    }

    __HAL_CAN_RESET_HANDLE_STATE(&hcan1); //

    /* CAN出错后重新配置CAN外设 */

    //bsp_can1Init();

  }

}


解决方法:将__HAL_CAN_RESET_HANDLE_STATE(&hcan1);也屏蔽掉,或者将can初始化函数取消注释。


关键字:STM32  使用过程  踩坑记录 引用地址:STM32使用过程中的踩坑记录

上一篇:stm32 bootloader启动正常,APP程序会在时钟配置出错原因分析
下一篇:彻底搞清printf在STM32上的使用

推荐阅读最新更新时间:2024-11-17 05:39

STM32 CAN总线传输波特率的计算
本人用的单片机是STM32F407,其它型号的单片机类似,可做参考! 一、标准CAN协议位时序概念 由于CAN属于异步通讯,没有时钟信号线,连接在同一个总线网络中的各个节点会像串口异步通讯那样,节点间使用约定好的波特率进行通讯。 同时,CAN还使用“位同步”的方式来抗干扰、吸收误差,实现对总线电平信号进行正确的采样,确保通讯正常。 为了实现这个位同步,CAN协议将每个位的时序分解为四段:SS段、PTS段、PSB1段、PBS2段。同时定义最小的时间单位:Tq,四个段的长度用x个Tq表示,加起来就是一个位的时序。 用一个图来表示可能会形象一点,如图一个位的时序就是19Tq。 以上就是CAN标准协议定义的位时序,而S
[单片机]
<font color='red'>STM32</font> CAN总线传输波特率的计算
stm32的断言机制(assert)的理解
在做stm32的库程序移植时出现错误“#error Please select first the target STM32F4xx device used in your application (in stm32f4xx.h file) ”,未选择STM32F4xx 设备导致多.h文件未被载入,发现是STM32F429_439xx的宏定义未定义,解决方法是在工具魔法棒 中的C/C++页的#define栏中添加相应的宏定义。 出现错误“.ObjectsSTM32F429IGT6_Demo.axf: Error: L6218E: Undefined symbol assert_param (referred from
[单片机]
<font color='red'>stm32</font>的断言机制(assert)的理解
STM32中关于高电平有效,低电平有效的一点理解
在学习STM32中的过程中,经常会遇到“高电平有效”,“低电平有效”等字眼,初看时很多时候就会从字面上理解,认为高电平有效的意思就是有效电平是高电平,低电平有效的意思就是有效电平是低电平的意思。而实际上,这样的理解是有误的。下面咱们以STM32的定时器中输出比较通道为例: 这幅图实际上就是一个pwm波产生的过程,对定时器不了解的可以去查阅相关手册,现在我们先看图中标号1的输出模式控制器,这里模式是指pwm模式,他的意思就是可以通过配置寄存器TIMx_CCMR1的OC1M两位,来选择pwm的模式,但是关于模式选择,手册中有这样一句话:在向下计数时,一旦TIMx_CNT TIMx_CCR1时通道1为无效电平(OC1REF=0),否
[单片机]
<font color='red'>STM32</font>中关于高电平有效,低电平有效的一点理解
stm32通用定时器的PWM输出
配置过程:(以TIM3为例,其CH1-CH4为:PA6、PA7、PB0、PB1) 1)开启TIM3时钟,配置4个IO口为复用推挽输出。 2)设置TIM3的ARR和PSC来控制PWM的周期。 3)设置TIM3的CH1-CH4的PWM模式及通道方向,使能TIM3的CH1-CH4输出。 4)使能TIM3。 程序如下: /* * 函数名:TIM3_GPIO_Config * 描述 :配置TIM3复用输出PWM时用到的I/O * 输入 :无 * 输出 :无 * 调用 :内部调用 */ void TIM3_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; //PCLK1经
[单片机]
stm32单片机进入休眠模式后无法下载程序等问题的解决
利用stm32单片机的休眠模式,使单片机间歇的休眠从而实现低功耗的目的。往往会出现进入休眠后无法唤醒,导致下一次程序烧不进去。通常的解决办法是:一般的开发板或单片机最小系统都会有复位键,按住复位键,点下载,然后松开复位键即可。 我遇到的问题是:误入了stm32(STM32L051C6T6)的STOP模式,又没有写入相应的唤醒方法,导致后续的程序不能下载。使用MDK5 点击load时总会出现No target connected。自己设计的最小系统又没有加入复位键。。。 有以下几种解决办法: 1、可以将单片机的NRST引脚引出来,外接复位键。(关于引脚查看可用ST官方软件STM32cubeMX,很方便) 2、通过IS
[单片机]
<font color='red'>stm32</font>单片机进入休眠模式后无法下载程序等问题的解决
STM32学习笔记——TFT2.4彩屏显示图片
利用彩屏显示图片需要先完成彩屏的驱动程序,然后在驱动程序的基础上再编写应用程序。 彩屏的驱动程序如果写好的话,就可以一直使用了,精力主要集中在应用程序的编写就可以了,但是移植的话,要移植驱动程序。其实移植也只是改变那些很底层的靠近处理器的那部分代码。 因为STM32F103C8的片上只有64K的FLASH,所以不能存储太多的图片数据,也就不能显示太大的图片。 一下的程序注释的比较详细,看懂了基本上就可以用了。 彩屏驱动程序的头文件lcd.h如下: #define uchar unsigned char #define uint unsigned int #define Bus_16 //
[单片机]
关于STM32 ADC速度的问题
STM32F103xx系列称为增强型产品,增强型产品的最高时钟频率可以达到72MHz。增强型产品的英文名称为Performance Line。 STM32F101xx系列称为基本型产品,基本型产品的最高时钟频率可以达到36MHz。基本型产品的英文名称为Access Line。 根据设计,当ADC模块的频率为14MHz时,可以达到ADC的最快采样转换速度。 要得到14MHz的ADC频率,就要求SYSCLK的频率是14MHz的倍数,即14MHz、28MHz、42MHz、56MHz、70MHz、 84MHz等;对于基本型产品14MHz和28MHz处于它的最大允许频率范围内;对于增强型产品,14MHz、28MHz、42MHz、5
[单片机]
STM32 延时函数封装
/*--------------------------------- 延时模块函数 说明:只需在工程中加入delay.c和delay.h 文件,即可用 Delayms(__IO uint32_t nTime); Delayus(__IO uint32_t nTime) -----------------------------------*/ #ifndef __DELAY_H #define __DELAY_H #include "stm32f10x.h" /*--------------------------------- 描 述:参数1即为1ms,1000即为1s;只有几 us的误差; -----
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved