【问题标题】:Global variables are not initialized after program start程序启动后全局变量未初始化
【发布时间】:2017-09-12 21:52:20
【问题描述】:

我正在编程通过 UART 连接到我的 PC 的 STM32L152。

我使用 GNU Tools ARM Embedded 版本 6.2 2016q4。

编译器控制字符串:

-mcpu=cortex-m3; -mthumb; -Wall; -ffunction-sections; -g; -O0; -DSTM32L152RB; -DSTM32L1XX_MD; -I.; 

链接器控制字符串

-mcpu=cortex-m3; -mthumb; -g; -Map=mufs_stm32l152.map; -O0; --gc-sections; -L${linkdir}; -T${linkdir}/arm-gcc-link.ld;  

其实是Coocox IDE的默认值,我没改。

我的代码:

int main(void)
{
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);

    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    //PD6  -> RX UART.
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
    GPIO_InitStructure.GPIO_PuPd = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_8| GPIO_Pin_7| GPIO_Pin_6;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    //enable pin
    GPIO_SetBits(GPIOB, GPIO_Pin_9);

    RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
    USART1->CR1 |= USART_CR1_UE;
    USART1->CR1 &= ~USART_CR1_M;
    USART1->CR2 &= ~USART_CR2_STOP; 
    USART1->BRR = 139; //baud rate 115200 HSI = 16 МГц
    USART1->CR1 |= USART_CR1_TE;
    USART1->CR1 |= USART_CR1_RE;

    USART_ITConfig(USART1,USART_IT_RXNE, ENABLE);
    NVIC_EnableIRQ(USART1_IRQn);

    while(1)
    {}

}

char hh = 'G';
void USART1_IRQHandler(void)
{
    if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE))
    {
        char ch = USART_ReceiveData(USART1);
        USART_SendData(USART1, hh);
        if(ch == 'A')
            GPIO_ToggleBits(GPIOB, GPIO_Pin_8);

    }
}

当我在 PC 上按下按键时,我希望在控制台中看到类似这样的内容

GGGGGGGGGGGG

但我得到的只是一些垃圾。有时它是一些字母,有时它是不可打印的字符。在我编辑我的代码并重新编译它之前它不会改变。我可以分配价值并且它起作用。看起来全局变量hh 没有她的初始值。此外,如果我将其标记为常量,它会按预期开始工作。

我做错了什么?

【问题讨论】:

  • 它是依赖于工具链的 C 运行时启动,它负责静态初始化 - 有些人可以选择根本不这样做。您使用的是什么工具链?你忽略了重要的信息。你也可以用一个更简单的例子重现这个问题。即只是一个全局初始化,然后在您的调试器中检查它,而不是通过串行输出间接推断 - 例如,折扣任何其他破坏您的全局的代码。如果它在您分配值时有效,那么包含该版本的代码而不是仅仅描述它会很有用。
  • 只有按键才看到垃圾吗?如果有,一般是在主机上未正确初始化UART(波特率、流控、数据位、停止位)时发生的
  • @Clifford 谢谢您的回复!我添加了有关我的工具链的信息。我已经在调试器中检查了变量,它在主函数开始时没有初始化。
  • @OlivierM 请看我对 Clifford 的评论。问题不在 UART 中。如果我为全局变量分配一些值,它会很好地工作。
  • 在不了解您的工具链的情况下,我无法详细说明。您是否研究过链接器的节设置的布局和属性?例如。对于我的工具链,我会识别并研究一个文件“something.ld”。对于显式初始化的全局变量,我希望有一个 data 部分和类似 data.rom 部分的内容,从中将值复制到代表变量的内存位置。然后这两个部分需要设置几个适当的属性。它们又应由 C 运行时环境“CRT”在启动 main() 之前处理。

标签: c stm32 stm32l152


【解决方案1】:

在 CooCox IDE (v1.7.6) 中,全局变量(实际上是数据段)的初始化在 startup_stmxxxxxx_md.c 文件中的 Default_Reset_Handler 函数中执行。而且我不知道这有什么意义,但在我的案例中,执行data 段初始化以及bss 零填充的代码默认被注释掉了。对于正确的变量初始化,您应该取消注释此代码。

【讨论】:

  • startup_stmxxxxxx_md.c 代码最初由 ST 提供(查看您版本中的样板/版权注释以确认)。在原始代码中,它没有被注释掉——也许它是由您团队中的某个人完成的,从另一个项目复制的,甚至是由 coocox.org 完成的,但肯定不是 ST。我的建议是从 ST 获取最新的设备支持代码 - 它包含在他们的标准外围库示例中。
  • 这不是您正在使用的 C 库的一部分吗?应该有一个 C 库入口点,它作为 reset_handler 的一部分被调用,它将初始化诸如 RW 数据段、BSS 段和堆之类的东西。
  • @Flip No. 据我所知,它不是 C lib 的一部分。它只是按字节将数据从 FLASH 复制到 SRAM。
  • @KonstantinT,是的,这就是 C 真正需要的。那并将BSS部分归零。但是通常有一些库例程可以执行此操作,或者您必须手动提供。在ARMCC中是工具链在幕后插入的分散加载部分。在 GCC 中,我相信您可能必须手动提供,尽管网络上有示例。使用 C++,您还需要调用静态对象的构造函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多