视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
stm32开发问题集锦
2025-09-26 22:00:20 责编:小OO
文档
[本文摘自:http://hi.baidu.com/govern/blog/category/it%CE%C4%D5%C2]

1 在flash中跑程序时,能进入中断,但在ram中跑时,进不了中断的原因。

看以下的中断配置函数可以知道,要在ram中调试程序,需要定义VECT_TAB_RAM。

定义方法a:在Project\\Options for taget 'xxx' 的对话框的c/c++中定义宏VECT_TAB_RAM

定义方法b:在程序中直接定义

void NVIC_Configuration(void)

{

NVIC_InitTypeDef NVIC_InitStructure;

#ifdef VECT_TAB_RAM 

/* Set the Vector Table base location at 0x20000000 */ 

NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); 

#else /* VECT_TAB_FLASH */

/* Set the Vector Table base location at 0x08000000 */ 

NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0); 

#endif

/* Configure and enable ADC interrupt */

NVIC_InitStructure.NVIC_IRQChannel = ADC1_2_IRQChannel;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

2 SysTickHandler 函数不能进入。

原先初始化的语句为

SysTick_Config();

修改为以下时可以进入

SysTick_Config();

SysTick_CounterCmd(SysTick_Counter_Enable); 

3 如何解决链接时错误"..\\obj\\LowCostDA.axf: Error: L6218E: Undefined symbol assert_failed (referred from stm32f10x_flash.o)."?

如果所加入的库是STM32F10xD.LIB(即调试模式库),则需要在无论什么得放添加函数定义

void assert_failed(u8* file, u32 line)

/* User can add his own implementation to report the file name and line number,

     ex: printf("Wrong parameters value: file %s on line %d\\r\\n", file, line) */ /* Infinite loop */

while (1)

{

}

}

如果所加入的库是STM32F10xR.LIB(即发布模式库),则不会报错。 

4 打开中断的时机不正确,导致无法进行任务切换。

由于我过早地打开了 SysTick 中断,而我在SysTickHandler 中有如下语句:

{

...

OS_ENTER_CRITICAL(); /* Tell uC/OS-II that we are starting an ISR */

    OSIntNesting++;

    OS_EXIT_CRITICAL();

    OSTimeTick();        /* Call uC/OS-II's OSTimeTick()               */

    OSIntExit(); 

...

}

因为打开过早,因此 OSIntNesting++ 能够执行,而OSIntExit函数却没有把OSIntNesting减1.因此,导致了无法进行任务切换。

注意2点可以避免该情况:

a 同时使用 OSIntExit(); 和OSIntEnter(); 而不是像我这样使用OSIntNesting++ 和OSIntExit()。

b 开中断要在操作系统初始化后完成,即在OSStart之后。

5 程序中只要使用了printf函数,就会执行到BKTP语句挂掉。

解决方法:Project\\Options Target选项页中选中 Use MicroLIB

关于 MicroLIB的详细说明见网友文章

http://hi.baidu.com/tt_gt/blog/item/8320b3dd7b3da2d38c1029e8.html

6 参考99的rtc时钟的使用方法,出现问题并顺利解决。

在程序中我修改当前时间是调用的以下函数

void Time_SetUnixTime(time_t t)

{

   RTC_WaitForLastTask();

   RTC_SetCounter((u32)t);

   

   RTC_WaitForLastTask();

   return;

}

但是程序会一直运行在 RTC_WaitForLastTask 中无法出来。

最终顺利解决。

99所介绍的程序启动是配置rtc的函数如下:

void RTC_Config(void)

{

   //我们在BKP的后备寄存器1中,存了一个特殊字符0xA5A5

   //第一次上电或后备电源掉电后,该寄存器数据丢失,

   //表明RTC数据丢失,需要重新配置

   if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)

   {

       //重新配置RTC

       RTC_Configuration();

       //配置完成后,向后备寄存器中写特殊字符0xA5A5

       BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);

   }

   else

   {

       //若后备寄存器没有掉电,则无需重新配置RTC

       //这里我们可以利用RCC_GetFlagStatus()函数查看本次复位类型

       if (RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET)

       {

           //这是上电复位

       }

       else if (RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET)

       {

           //这是外部RST管脚复位

       }

       //清除RCC中复位标志

       RCC_ClearFlag();

       //虽然RTC模块不需要重新配置,且掉电后依靠后备电池依然运行

       //但是每次上电后,还是要使能RTCCLK?

       //RCC_RTCCLKCmd(ENABLE);

       //等待RTC时钟与APB1时钟同步

       //RTC_WaitForSynchro();

       //使能秒中断

       RTC_ITConfig(RTC_IT_SEC, ENABLE);

       //等待操作完成

       RTC_WaitForLastTask();

   }

#ifdef RTCClockOutput_Enable

   /* Enable PWR and BKP clocks */

   RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

   /* Allow access to BKP Domain */

   PWR_BackupAccessCmd(ENABLE);

   /* Disable the Tamper Pin */

   BKP_TamperPinCmd(DISABLE); /* To output RTCCLK/ on Tamper pin, the tamper

                               functionality must be disabled */

   /* Enable RTC Clock Output on Tamper Pin */

   BKP_RTCOutputConfig(BKP_RTCOutputSource_CalibClock);

#endif

   return;

要调用Time_SetUnixTime设置时间 应该在if分支里边。

而不是在else分支里边。

我正好是犯了这样的错误。

7 关于堆栈对齐的问题

程序中出现了一个奇怪的问题

char g_cpTask2Buffer[200];

void Task2(void *arg)

{

...

sprintf(g_cpTask2Buffer,"%.3f", ADCInfoArray[0].m_fVolt); 

...

}

ADCInfoArray[0].m_fVolt是一个float值。

在执行完 sprintf 后,无论m_fVolt是多少,始终得到的g_cpTask2Buffer的内容都是"0.000"。

调试了好几天的汇编终于解决了问题,根源竟然是ucos的堆栈需要以8字节对齐。

Task2是一个ucos的任务,Stack2 是Task2的任务堆栈。

如果是以下形式则出错:

Stack2                                   0x200084ac   Data         804 main.o(.bss)

Stack3                                   0x200087d0   Data         800 main.o(.bss)

如果是以下形式则不出错:

Stack2                                   0x200084ac   Data         800 main.o(.bss)

Stack3                                   0x200087cc   Data         800 main.o(.bss) 

为什么 sprintf在Task2 的中,但是执行结果的正确与否却看起来似乎与Task3的任务堆栈Stack3相关?

原因是,任务 Task2 的堆栈顶实际上位于Stack2 + (Stack2STKSIZE - 1),该值正好与Stack3 

相连。

为什么堆栈必须要8字节对齐?

因为在汇编中有这样的语句:

BIC      r0,r2,#0x07   

该句得到double型值(在处理过程中,m_fVolt先从float被转换为double型) 的存储地址。

该汇编的意思是把r2的最低一个字节的二进制最后3位清零,即把r2变为形如16进制xxxxxxx0或者xxxxxxx8,然后放入r0。

可以看到该地址必然是8字节对齐的。

最根本的原因我仍然没有找到,但算是解决了问题。

8 外部sram用作堆栈的一个问题

系统中使用了ucos,由于任务堆栈的空间需要的比较多,因此把其放到了外部sram中,使用这样的语句:

OS_STK Stack1[STKSIZE] __at (Bank1_SRAM3_ADDR) ;

但是没有想到的是,在使用sdio方式操作sd卡时,总是出现SDIO_IT_TXUNDERR 中断。

没有好的解决办法,只能老老实实地把任务堆栈放入片内的sram。

想来,恐怕原因是系统在和SD卡交换数据时用到了任务堆栈区,而任务堆栈区所在的片外的sram速度不够快导致的问题。

虽然问题凑合解决了,但是问题仍然存在:

外部sram到底能怎么用? 如果外部sram能和片内的sram一样方便地使用就好了。

看到这篇博客的朋友,有没有什么好的解决办法?

9 闹钟中断的问题(RTCAlarm)

打算在standby模式下使用闹钟中断,但由于standby模式调试不方便 ,因此在正常运行状态下先测试闹钟中断。

没想到遇到了问题:

关掉了RTC_IRQHandler,只打开RTCAlarm_IRQHandler。但是依然能进入RTC_IRQHandler中断函数,但不是正常状态下的进,而是不停地进中断,

而且RTC_GetITStatus(RTC_IT_SEC)得到状态也确实不是秒中断发生。

同时,也会进RTCAlarm_IRQHandler中断,也不是正常状态下的进,而是不停地进中断,而且RTC_GetITStatus(RTC_IT_ALR)得到状态也确实不是闹钟中断发生。

最终找到了问题所在:

一定要在RTCAlarm_IRQHandler函数中有这句:EXTI_ClearITPendingBit(EXTI_Line17);

郁闷啊,小小的问题,找了一下午。下载本文

显示全文
专题