赞
踩
1.使用rtthread时,bootloader跳转后就跳转到错误函数中,无法正常运行,debug发现,问题是时钟再次被配置引起,解决方案:将app的时钟配置函数注释,只在bootloader中调用一次时钟配置。
2.使用C++打印异常信息只能打印出 std::exception,无法打印具体异常,解决方法:使用引用即可正常打印
- catch(exception& e){
- const char* errorMessage = e.what();
- printf("初始化发生异常:%s\n",errorMessage);
- }
3.异常出现std::bad_alloc,表示new 操作错误,堆栈不够大,调整Heap_Size解决
4.使用bootloader下载程序到内部flash后,总是校验不通过,发现有的扇区的数据不正确,最终问题原因:#define FLASH_MASK 0x7FF 这个值从0x3ff改为0x7ff后下载正常
5.串口中断溢出解决:
在错误函数中调用SR 和DR 清除中断标志,并且重新开启中断
- void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
- {
- __HAL_UART_CLEAR_IDLEFLAG(huart);
- rx=huart->Instance->SR;
- rx=huart->Instance->DR;
- HAL_UART_Receive_IT(huart, &rx,1);
-
- }
6.STM32 内部flash 读写错误:
首先需要擦除扇区才能进行写入,否则会写入失败返回HAL_ERROR,并且存放的位置必须不能跨扇区存放,否则就要多擦除一个扇区。
- uint32_t PageError = 0;
- FLASH_EraseInitTypeDef pEraseInit;
- pEraseInit.TypeErase = FLASH_TYPEERASE_PAGES;
- pEraseInit.PageAddress = LOSS_ADDR & ~(FLASH_PAGE_SIZE - 1);
- pEraseInit.NbPages = 1;
- HAL_FLASHEx_Erase(&pEraseInit, &PageError);
首先擦除,然后进行写入,PageAddress直接填入地址,不用计算扇区!
- if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,LOSS_ADDR+i, data)!=HAL_OK){
- printf("写入失败add:%x",LOSS_ADDR+i);
- //return 1;
- };
读取:
- HAL_FLASH_Unlock();
- memcpy(buffer,(uint8_t*)ADDR,size);
- HAL_FLASH_Lock();
7.串口接收一段时间后就无法接收到数据了,解决方法:
在串口错误中断函数里清除中断标志后,加入重新开启HAL_UART_Receive_IT(huart, &rx,1);即可
8.编码器测速脉冲数量和实际不同
问题解决:
- htim2.Instance = TIM2;
- htim2.Init.Prescaler = 3;
- htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
- htim2.Init.Period = 0xFFFF;
- htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
- htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
- sConfig.EncoderMode = TIM_ENCODERMODE_TI12;//正交编码器模式 T1T2
- sConfig.IC1Polarity = TIM_ICPOLARITY_BOTHEDGE;
- sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
- sConfig.IC1Prescaler = TIM_ICPSC_DIV1;
- sConfig.IC1Filter = 0;
- sConfig.IC2Polarity = TIM_ICPOLARITY_BOTHEDGE;
- sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
- sConfig.IC2Prescaler = TIM_ICPSC_DIV1;
- sConfig.IC2Filter = 0;
- if (HAL_TIM_Encoder_Init(&htim2, &sConfig) != HAL_OK)
- {
- Error_Handler();
- }

其中Prescaler 是设为0时获得的数量除以实际的数量比值,比如0是256,实际是64,那么Prescaler设为3。这个值是指脉冲数量的分频而不是时钟的分频!
Period 为最大计数值,而不是触发脉冲的装填值
IC1Polarity 和IC2Polarity 要设置为TIM_ICPOLARITY_BOTHEDGE 脉冲数量更准
9.配置完唤醒脚之后,休眠立即自动唤醒:
解决方法:添加最后两行代码解决
- __HAL_RCC_GPIOC_CLK_ENABLE();
-
- GPIO_InitTypeDef GPIO_InitStruct = {0};
- GPIO_InitStruct.Pin = GPIO_PIN_5;
- GPIO_InitStruct.Pull = GPIO_PULLUP;
- GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
- HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
-
-
- HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN5);//按键唤醒
-
- GPIO_InitStruct.Pin = GPIO_PIN_13;
- GPIO_InitStruct.Pull = GPIO_PULLDOWN;
- GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
- HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
- HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN2);//设备唤醒
- //响应3 ,抢占0
- __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
- // //暂停滴答时钟,防止通过滴答时钟中断唤醒
- HAL_SuspendTick();

10.SSD1306 OLED硬件SPI无法驱动:
解决方法:spi配置中,必须设置以下几项:
hspi3.Init.Direction = SPI_DIRECTION_2LINES;//之前无法驱动就是因为设置成了1LINES
hspi3.Init.DataSize = SPI_DATASIZE_8BIT;//数据位是8位
hspi3.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;//波特率可以设置高一些,设置2,4,8等都可以驱动
11.串口DMA无法收发:
解决方法:DMA初始化中,忘了加入响应DMA通道的中断,所以无法收发数据,必须加上才行
- HAL_NVIC_SetPriority(DMA2_Channel6_IRQn, 0, 0);
- HAL_NVIC_EnableIRQ(DMA2_Channel6_IRQn);
- /* DMA2_Channel2_IRQn interrupt configuration */
- HAL_NVIC_SetPriority(DMA2_Channel7_IRQn, 0, 0);
- HAL_NVIC_EnableIRQ(DMA2_Channel7_IRQn);
12.nfc通信中途断开:
解决方法:将26改成27增加连接等待延迟
- /*! Maximum Frame Waiting Time = ((256 * 16/fc) * 2^FWImax) = ((256*16/fc)*2^14) = (67108864)/fc = 2^26 (1/fc) */
- #define RFAL_ISODEP_MAX_FWT ((uint32_t)1U<<27)
13.程序运行死机,发现串口中断一直进入,断点无法命中。
解决方法:在初始化的时候错误启用了串口空闲中断,必须关闭它才可以完成初始化
__HAL_UART_ENABLE_IT(&LOAD_UART, UART_IT_IDLE);
14.DMA接收数据不进入rx完成中断函数:
这是由于DMA接收必须数量达到调用时填入的数量才会触发中断。要采用空闲中断触发的方式才能进入中断。
15.用C++创建智能指针后,出现崩溃
- //错误代码,没有保存unique对象会导致其创建后立即销毁,从而导致model是一个空指针,继续使用从而引起异常
- auto model = std::make_unique<PersonModel>().get();
16.使用指针发送数据时,发送的数据不正确
解决方法:这里在if里面再次定义了buffer,而send函数是在if外面,于是使用了外面定义的空指针,从而导致了数据不正常。正确写法应该是将if里的类型去掉直接写 buffer = get_buffer();
- uint8_t* buffer;
- if(...){
- uint8_t* buffer = get_buffer();
- }
- send_buffer(buffer,1024);
17.DMA串口发送的时候,数据不正常,原因:DMA发送函数只是把数组指针告诉了dma发送器,而函数退出后,数组被释放,数据也就不正常了,因此需要把发送数组设为全局或等待发送完成才能退出函数。
18.使用L431擦除页的时候,擦除不完整导致数据写入错误,校验不通过
解决方法:擦除页面只需要计算页地址和结束地址,而不需要一页一页的擦除,支持多页擦除,因此可以使用多页擦除的方式
- //将原来的一页擦除方式改成由尾页-首页得到页面的总数量,然后将页数赋值给NbPages,就可以实现一次擦除多个页,原来的一页擦除方式需要计算页地址和擦除次数,因此是错误的
- // do
- {
- //BSP_WDGReboot();
- EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
- EraseInitStruct.Banks = bank;
- EraseInitStruct.Page = FirstPage;
- EraseInitStruct.NbPages = GetPage(start+size) - FirstPage + 1;
- //EraseInitStruct.NbPages = 1;
- if(HAL_FLASHEx_Erase(&EraseInitStruct, &page_error) != HAL_OK)
- result = HAL_ERROR;
-
- // FirstPage = GetPage(start);
- // page_size = FLASH_PAGE_SIZE;
- // start += page_size;
- // size = (size>=page_size)?(size-page_size):0;
- HAL_Delay(1);
- }
- // while(size);

19.给人脸模块发送串口数据时,经常发送失败,并且人脸模块发生阻塞,无法再收到数据:
经过分析,人脸模块最大缓冲只有4k,当错误数据超过4k后就无法收到任何数据了,那么就是数据发送有问题,怀疑是数据间隔过大。解决方法:将中断禁用然后发送数据就不会被干扰了
- __disable_irq();
- HAL_UART_Transmit(&huart3, txbuffer, txlen, 0xffff);
- __enable_irq();
20.使用内部硬件看门狗休眠后立即被唤醒
解决方法:内部看门狗只有复位才能关闭,因此需要定义noinit变量,复位重启后判断该变量直接进入休眠
21.单片机在开机时无法进入休眠:
- void enter_stop(){
- //修改noinit变量
- (*(uint32_t*)0x2000FFFC)=25;
- ...
- //然后重启
- }
解决方法:并且休眠函数必须在HAL_init函数调用之后调用,如果在HAL_Init()之前调用,则无法唤醒
- HAL_Init();
- if((*(uint32_t*)0x2000FFFC)==25){
- (*(uint32_t*)0x2000FFFC)=0;
-
- awak_pin_init();
- __disable_irq();
- HAL_PWR_EnterSTANDBYMode();
- }
- MX_GPIO_Init();
22.定义的noinit地址变量总是被修改:
解决方法:在应用中将地址变量赋值后重启进入到bootloader内部,此时执行了HAL_Init();而这个函数可能会在最结尾的内存地址上连续写入,将会覆盖掉0x2000FFF8以后的内容,因此导致了变量无效。booltloader中可以将内存大小进一步减少:限制其内存范围
这样bootloader启动时就不会将0x2000FFF8的内容覆盖。
23.使用LVGL时发生硬件错误,原因是带数据的事件发送速度过快,LVGL分配内存释放速度跟不上,导致分配出错。
解决方法:
发送事件之间增加10ms延迟,仅仅能够降低出错的概率,并不能完全解决问题
24.bootloader每次启动时随机发生死机,但是将串口线插上就不会发生死机,且不同板子死机概率不同,代码程序都完全相同。
解决方法:在串口1中发现串口定义没有使用上拉电阻,怀疑是串口受到了干扰,并且启动到串口开启中断时就会导致死机。将串口上拉电阻加上就解决了
- GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
- GPIO_InitStruct.Pull = GPIO_PULLUP;
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
- GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
25.使用lvgl时在显示画面文字时偶尔发生死机,发生段错误
解决方法:经过排查,lvgl在设置文本时会分配内存,并且lv_task_handle和lv_tick是在中断中调用的,LVGL默认线程不安全,因此要增加线程锁,如果是在rtos环境中使用多线程修改控件内容,那么该操作也必须增加线程锁,如果只是在lvgl内部事件回调中修改控件,那么就是执行在lv_task_handle函数里,可用不加锁
- lv_lock();
- lv_tick_inc(1);//这两个函数在中断中调用会发生资源竞争
- lv_unlock();
-
-
- lv_lock();
- lv_task_handler();//这两个函数在中断中调用会发生资源竞争
- lv_unlock();
-
- void lv_lock(){
- if(lv_mutex==1)
- return;
-
- lv_mutex=1;
-
- }
- void lv_unlock(){
- lv_mutex=0;
- }

26.系统随机发生死机现象,发现是内存泄漏导致
//printf("写入人脸特征:%s\n",Hex2Str(face_buffer,1024).c_str());
打印这段代码也发生内存泄漏,分析原因,可能是此函数内创建了过多的字符串对象,而无法申请到内存导致内存泄漏,并且函数使用c_str,可能导致返回的string对象提前释放内存,而导致%s访问到越界的字符串,从而导致卡死。
解决方法:使用返回string的字符串要先保存对象,再访问
auto feature_str=Hex2Str(feature_buffer.get(),1024);
并且将Hex2Str内改为使用append,此函数可以在原来对象上增加字符串,而不是频繁创建string对象
- string Hex2Str(uint8_t *sSrc, int nSrcLen )
- {
- int i;
- string sDest="";
- char szTmp[3];
-
- for( i = 0; i < nSrcLen; i++ )
- {
-
- sprintf( szTmp, "%02X",sSrc[i] );
- sDest.append(string(szTmp));//此处改为使用append ,而不是使用sDest+=string(szTmp)
- }
- //printf("fece:%s\n",sDest.c_str());
- return sDest;
- }
27.使用LVGL随机发生死机现象,发现是lv_handle_task在中断中调用发生了重入,将其放在循环内调用可以解决,或者在中断中增加停止中断的代码
- void TIM7_IRQHandler(void)
- {
-
- if(lv_task_run==false){
- lv_task_run=true;
- HAL_TIM_Base_Stop_IT(&htim7);
- lv_task_handler();
-
- HAL_TIM_Base_Start_IT(&htim7);
- HAL_TIM_IRQHandler(&htim7);
- lv_task_run=false;
- }
- }
28.串口发送数据发生死机,每次都是死在 HAL_UART_Transmit (&hlpuart1,(uint8_t*)&pack,sizeof(RWTdata_system),0xffff);
后面将HAL_UART_Transmit 改成HAL_UART_Transmit_DMA问题解决,问题根本原因是串口上焊接了电容,导致发送时产生了同时收发电压,引起串口错误
29.LVGL在定时器中调用lv_task_handle 后,在循环中使用lv_event_send,偶尔出现死机,并且发送事件频率越高,或者是定时器越慢死机概率越大,说明lv_task_handle执行越快,事件发送的可能就越低,而被打断的机会就越少,因此死机频率降低。
解决方法:定时器中要禁用定时器中断,防止lv_task_handle重入,第二使用mutex防止lv_event_send执行中被打断直接执行lv_task_handle,引起LVGL内部混乱,LVGL的各个函数只能顺序执行,不能交叉执行,一个函数必须运行完成才能执行下一个函数。
- //将发送事件函数封装加入互斥量
- void disp_event_send(lv_obj_t * obj, lv_event_code_t event_code, void * param){
- while(lv_task_run==true);
- lv_task_run=true;
- lv_event_send(obj,event_code,param);
- lv_task_run=false;
- }
- void TIM7_IRQHandler(void)
- {
- //加入互斥量
-
- if(lv_task_run==false){
- lv_task_run=true;
- HAL_TIM_Base_Stop_IT(&htim7);
- lv_task_handler();
-
- HAL_TIM_Base_Start_IT(&htim7);
- lv_task_run=false;
- }
-
- HAL_TIM_IRQHandler(&htim7);
-
- }

30.ABOV G123检测发送器缓冲寄存器死循环,解决方法:
UART1->LST_b.THRE 必须加上括号再进行!判断,如果直接写成
- while( !UART1->LSR_b.THRE);//在某些编译器下会造成无法获取到寄存器的值
- while( !(UART1->LSR_b.THRE));//必须加上括号
- //重定向fputc函数
- int fputc(int ch, FILE *f) //两个标准参数
- {
- //将要发送的数据通过串口1发送出来(可以用电脑上的串口调试软件接收)
- UART1->THR=ch;
-
- //等待发送是否完成
- while( !(UART1->LSR_b.THRE));
- //while( !( UART1->LSR & UARTn_LSR_THRE ) );
-
- return ch;
- }
-
31.关闭网口模块电源后,其串口发生中断并且无法退出导致程序死机在中断里,解决方法:
增加deinit串口的代码,可以将串口关闭
- #define bsp_set_wk_off() {\
- HAL_GPIO_WritePin(IO_INWK_GPIO_Port, IO_INWK_Pin, GPIO_PIN_RESET);\
- HAL_UART_DeInit(&huart6);\
- }
- #define bsp_set_wk_on() {\
- HAL_GPIO_WritePin(IO_INWK_GPIO_Port, IO_INWK_Pin, GPIO_PIN_SET);\
- HAL_UART_Init(&huart6);\
- }
32.使用 rtthread +网口串口发送数据后接收时,程序发生死机,屏蔽主函数循环后正常,解决方法:由于rt_event_send且没有接收事件的处理函数导致bug,取消事件发送解决
- void UART6_DMAReceved(uint16_t size)
- {
-
- usUART6_Length = size;
-
- HAL_UART_Receive_DMA(&huart6, (uint8_t*)acUART6_char, FINSH_BUF_SIZE);
- bsp_recive_data(acUART6_char,usUART6_Length);
- // rt_event_send(&event_task, TASK_EVENT_UART6);
-
-
-
- }
33.使用rtthread-studio 使用cubemax更新后,sdio不能使用了
解决方法:使用cubemax更新后文件被排除编译了,打开文件属性取消勾选将资源从构建中排除
34.接收数据时只要不加入printf("rx:%s dma:%d\n",aucTCP232_Buffer,dma_num);buffer里的值就不正确,导致无法接收到网口数据
解决方法:是程序中有数组越界导致增加清除信号量代码
- bsp_uart_send(at,length);
- ret = rt_sem_take(&sem_uart, 1000);
- printf("rx:%s dma:%d\n",aucTCP232_Buffer,dma_num);
-
- if(usTCP232_Size && bTCP232_Echo)
- {
- aucTCP232_Buffer[usTCP232_Size] = 0;
- APP_TRACE("tcp232 rx: \"%s\"\n\n", aucTCP232_Buffer);
- }
- rt_sem_control(&sem_uart, RT_IPC_CMD_RESET, RT_NULL);
-
- bsp_uart_send(at,length);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。