STM32编程提示和问题

时间:2011-11-12 19:51:52

标签: embedded arm cortex-m3 stm32

我在网上找不到关于STM32编程的任何好文件。 STM自己的文档没有解释注册函数。如果有人能解释我的以下问题,我将不胜感激?

  1. 我注意到在STM提供的所有示例程序中,main()的局部变量总是在main()函数之外定义(偶尔使用static关键字)。有什么理由吗?我应该遵循类似的做法吗?我应该避免在main中使用局部变量吗?

  2. 我有一个gloabal变量,它在时钟中断句柄中更新。我在另一个函数中使用相同的变量作为循环条件。我不需要使用某种形式的原子读取操作来访问此变量吗?我怎么知道时钟中断在函数执行过程中不会改变它的值?我是否需要在每次需要在函数内使用此变量时取消时钟中断? (但是,这对我来说似乎非常无效,因为我将它用作循环条件。我相信应该有更好的方法)。

  3. Keil自动插入以汇编语言编写的启动代码(即startup_stm32f4xx.s)。此启动代码具有以下import语句:     IMPORT SystemInit     IMPORT __main 在“C”中,它是有道理的。但是,在C ++中,main和system_init都有不同的名称(例如_ int _main__void)。即使不使用“extern”C“”(我试过并且它有效),这个启动代码如何仍然可以在C ++中工作。 c ++链接器(armcc --cpp)如何将这些语句与正确的函数相关联?

3 个答案:

答案 0 :(得分:4)

您可以使用本地或全局变量,在嵌入式系统中使用本地存在您的堆栈与数据冲突的风险。与全局变量你没有这个问题。但无论你身在何处,嵌入式微控制器,台式机等都是如此。

我会在使用它的前台任务中制作全局副本。

unsigned int myglobal;

void fun ( void )
{
   unsigned int myg;

   myg=myglobal;

然后只使用myg来完成剩下的功能。基本上您正在拍摄快照并使用快照。如果你正在阅读一个寄存器,你会想要做同样的事情,如果你想根据一个样本的样本做一些样本,并对那个样本做出决定,否则项目可以在样本之间改变。如果你使用一个全局来回与中断处理程序进行通信,那么我会使用两个变量一个前台来中断,另一个中断到前台。是的,有时你需要仔细管理这样的共享资源,通常它与你需要做多件事的时间有关,例如,如果你有几个项目都需要在一个组之前更改处理程序可以看到它们发生变化,然后你需要禁用中断处理程序,直到所有项都发生了变化。在这里,嵌入式微控制器没有什么特别之处,这是您在具有完整操作系统的桌面系统上看到的所有基本内容。

Keil知道他们在做什么,如果他们支持C ++,那么他们就可以从系统级别开始。我不使用Keil我使用gcc和llvm这样的微控制器。

编辑:

以下是我所谈论的一个例子

https://github.com/dwelch67/stm32vld/tree/master/stm32f4d/blinker05

stm32使用基于计时器的中断,中断处理程序修改与前台任务共享的变量。前台任务获取共享变量的单个快照(每个循环),如果需要在循环中多次使用快照而不是可以更改的共享变量。这是C而不是C ++我理解,我使用的是gcc和llvm而不是Keil。 (注意llvm已经知道优化紧密循环的问题,非常老的bug,不知道为什么他们没有兴趣修复它,llvm适用于这个例子)。

答案 1 :(得分:4)

问题1:本地变量

ST提供的示例代码不是特别有效或优雅。它完成了工作,但有时他们所做的事情没有充分的理由。

通常,您总是希望变量具有尽可能小的范围。如果只在一个函数中使用变量,请在该函数内定义它。当且仅当在函数完成后需要它们保留它们的值时,才将“static”关键字添加到局部变量。

在某些嵌入式环境中,如带有C18编译器的PIC18架构,局部变量比全局变量更昂贵(程序空间更多,执行时间更慢)。在Cortex M3上,这不是真的,所以你应该随意使用局部变量。检查装配清单并亲自查看。

问题2:在中断和主循环之间共享变量

人们写完整章解释了这组问题的答案。无论何时在主循环和中断之间共享变量,都应该使用volatile关键字。可以原子方式访问32位或更少位的变量(除非它们未对齐)。

如果需要从主循环同时访问更大的变量或两个变量,则必须在访问变量时禁用时钟中断。如果您的中断不需要精确计时,这将不是问题。当您重新启用中断时,它会在需要时自动触发。

问题3:C ++中的主要功能

我不确定。您可以在目标文件上使用arm-none-eabi-nm(或工具链中调用的任何nm)来查看C ++编译器分配给main()的符号名称。我敢打赌,由于这个原因,C ++编译器不会破坏主函数,但我不确定。

答案 2 :(得分:2)

STM的示例代码不是良好编码实践的示例,它仅用于举例说明其标准外设库的使用(假设这些是您正在讨论的示例)。在某些情况下,可能是变量在main()外部声明,因为它们是从中断上下文(共享内存)访问的。也许有可能这样做只是为了允许在调试器中从任何上下文中监视变量;但这不是复制技术的理由。我对STM示例代码的看法是,即使作为示例代码,它通常也很差,更不用说从软件工程的角度来看。

在这种情况下,只要您没有使用多个写入器的读 - 修改 - 写语义,您的时钟中断变量就是原子级,只要它是32位或更低。你可以安全地拥有一个作家和多个读者。对于这个特定平台来说,情况确实如此,但不一定普遍;对于8位或16位系统,或者对于多核系统,答案可能不同。在任何情况下都应该声明变量volatile

我在使用Keil的STM32上使用C ++,没有问题。我不确定为什么你认为C ++入口点不同,它们不在这里(Keil ARM-MDK v4.22a)。例如,启动代码调用SystemInit()来初始化PLL和内存时序,然后调用执行全局静态初始化的__main(),然后在调用main()之前调用C ++构造函数以获取全局静态对象。如果有疑问,请逐步调试调试器中的代码。重要的是要注意__main()不是您为应用程序编写的main()函数,它是一个包含C和C ++不同行为的包装器,但最终会调用您的main()函数。