Bootstrap

STM32-- 调试- 延时、编译空循环

编译对空循环的处理,会影响堵塞延时效果,具体怎么处理的还不知道,只知道结果和现象。

模拟串口输出字符,用到延时函数,同样的延时函数,会有正常和不正常输出的情况;具体现象如下,

//这部分函数是可以正常输出串口数据的
//使用stm32f103vct6,逻辑分析仪测出来脉冲长度是8.5us,电脑端设置115200,可以正常接收到发送的数据

#define RCC_TX_PIN  RCC_APB2Periph_GPIOD
#define TX_PIN  GPIO_Pin_2
#define GPIO_PORT_TX GPIOD
#define RCC_RX_PIN  RCC_APB2Periph_GPIOC
#define RX_PIN  GPIO_Pin_8
#define GPIO_PORT_RX GPIOC

// #define BAUD_RATE 115200
// #define BIT_PERIOD_US (1000000 / BAUD_RATE) // 比特周期 (微秒)

#define BIT_PERIOD_US (80) // 约延时8.5us,



// 简单的延时函数
void delay_us(uint32_t us) {
    // uint32_t count = (SystemCoreClock / 1000000) * us / 5;
    while (us--) {
        __NOP();
    }
    // for(int i=0;i<us;i++)
    // {}  

    // int i;
    // while (i<us) {
    //     __NOP();
    // i++;
    // }
}

int cnt;
int Get_SysTimeMs__(){
    return cnt++;
}
int delay_us__(uint16_t us) {
    // uint32_t start = Get_SysTimeMs(); // 获取当前计数值
     Get_SysTimeMs__();

    //for(int i=0;i<us;i++)
    //{} 
    // int a=cnt++;
    // return a;

    // 等待指定的时间
    // while ((Get_SysTimeMs() - start) < us);
}




// 初始化 GPIO
void USART_SIM_GPIO_Init(void) {

    GPIO_InitTypeDef GPIO_InitStructure={0};
    // I2C_InitTypeDef I2C_InitStructure;
    
    // 使能I2C1和GPIOB时钟
    // RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_TX_PIN, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_RX_PIN, ENABLE);

        // 配置I2C1引脚 - PB6(SCL)和PB7(SDA)
    GPIO_InitStructure.GPIO_Pin = TX_PIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  // 输出
    GPIO_Init(GPIO_PORT_TX, &GPIO_InitStructure);
    
    // 配置I2C1引脚 - PB6(SCL)和PB7(SDA)
    GPIO_InitStructure.GPIO_Pin = RX_PIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  // 输入
    GPIO_Init(GPIO_PORT_RX, &GPIO_InitStructure);

    // 默认 TX 高电平(空闲状态)
    GPIO_SetBits(GPIO_PORT_TX,TX_PIN);

}

// 模拟串口发送一个字节
void UART_SendByte(uint8_t byte) {
    // 起始位:低电平
    // HAL_GPIO_WritePin(GPIO_PORT_TX, TX_PIN, GPIO_PIN_RESET);
    GPIO_ResetBits(GPIO_PORT_TX,TX_PIN);

    delay_us(BIT_PERIOD_US);

    // 数据位:逐位发送
    for (uint8_t i = 0; i < 8; i++) {
        if (byte & (1 << i)) {
            // HAL_GPIO_WritePin(GPIO_PORT_TX, TX_PIN, GPIO_PIN_SET); // 发送1
            GPIO_SetBits(GPIO_PORT_TX,TX_PIN);

        } else {
            // HAL_GPIO_WritePin(GPIO_PORT_TX, TX_PIN, GPIO_PIN_RESET); // 发送0
            GPIO_ResetBits(GPIO_PORT_TX,TX_PIN);

        }
        delay_us(BIT_PERIOD_US);
    }

    // 停止位:高电平
    // HAL_GPIO_WritePin(GPIO_PORT_TX, TX_PIN, GPIO_PIN_SET);
    GPIO_SetBits(GPIO_PORT_TX,TX_PIN);

    delay_us(BIT_PERIOD_US);
}

int fputc(int ch, FILE *p) {
    // 调用自定义的模拟串口发送函数
    UART_SendByte((uint8_t)ch);

    // 模拟串口中无需等待 TXE 标志位,因此省略
    // 如果模拟串口有类似机制,可以插入相关等待逻辑

    return ch;
}



发送:

printf("Ahello02\n");

printf("中文\n");

情况一

使用for循环,不需要Get_SysTimeMs__和delay_us__函数就能正常发送串口数据。

// 简单的延时函数

void delay_us(uint32_t us) {

    for(int i=0;i<us;i++)

    {}  

}

对应的汇编函数:

    delay_us

        0x08003b50:    2100        .!      MOVS     r1,#0

        0x08003b52:    e000        ..      B        0x8003b56 ; delay_us + 6

        0x08003b54:    1c49        I.      ADDS     r1,r1,#1

        0x08003b56:    4281        .B      CMP      r1,r0

        0x08003b58:    d3fc        ..      BCC      0x8003b54 ; delay_us + 4

        0x08003b5a:    4770        pG      BX       lr

此时延时正常,串口发送正常。

情况二

使用while循环,有Get_SysTimeMs__函数也不能正常发送串口数据。

只有delay_us函数,使用while循环,发送串口数据更是乱码。

// 简单的延时函数

void delay_us(uint32_t us) {

    while (us--) {

        __NOP();

    }

}

int cnt;

int Get_SysTimeMs__(){

    return cnt++;

}

对应的汇编函数

    delay_us

        0x08003b50:    e000        ..      B        0x8003b54 ; delay_us + 4

        0x08003b52:    bf00        ..      NOP      

        0x08003b54:    1e40        @.      SUBS     r0,r0,#1

        0x08003b56:    1c41        A.      ADDS     r1,r0,#1

        0x08003b58:    d1fb        ..      BNE      0x8003b52 ; delay_us + 2

        0x08003b5a:    4770        pG      BX       lr

    Get_SysTimeMs__

        0x08003b5c:    4a49        IJ      LDR      r2,[pc,#292] ; [0x8003c84] = 0x200000b4

        0x08003b5e:    6810        .h      LDR      r0,[r2,#0]

        0x08003b60:    1c41        A.      ADDS     r1,r0,#1

        0x08003b62:    6011        .`      STR      r1,[r2,#0]

        0x08003b64:    4770        pG      BX       lr

不能正常串口数据,乱码

[19:16:49.820]收←◆羑ello02

中文

[19:16:51.334]收←◆夾he靗o02

中文

[19:16:52.847]收←◆Ahello?

中文

[19:16:54.360]收←◆Ah錶lo02

中文

[19:16:55.873]收←◆Ahello?

中文

[19:16:57.387]收←◆Ahello?

中文

[19:16:58.900]收←◆Ahello02娭形?

[19:17:00.413]收←◆Ah錶lo0?

中文

情况三

使用while循环,后面紧接着Get_SysTimeMs__和delay_us__函数,可以正常发送串口函数。

// 简单的延时函数

void delay_us(uint32_t us) {

    while (us--) {

        __NOP();

    }

}

int cnt;

int Get_SysTimeMs__(){

    return cnt++;

}

int delay_us__(uint16_t us) {

    Get_SysTimeMs__();

}

对应汇编函数

    delay_us

        0x08003b50:    e000        ..      B        0x8003b54 ; delay_us + 4

        0x08003b52:    bf00        ..      NOP      

        0x08003b54:    1e40        @.      SUBS     r0,r0,#1

        0x08003b56:    1c41        A.      ADDS     r1,r0,#1

        0x08003b58:    d1fb        ..      BNE      0x8003b52 ; delay_us + 2

        0x08003b5a:    4770        pG      BX       lr

    Get_SysTimeMs__

        0x08003b5c:    4a4a        JJ      LDR      r2,[pc,#296] ; [0x8003c88] = 0x200000b4

        0x08003b5e:    6810        .h      LDR      r0,[r2,#0]

        0x08003b60:    1c41        A.      ADDS     r1,r0,#1

        0x08003b62:    6011        .`      STR      r1,[r2,#0]

        0x08003b64:    4770        pG      BX       lr

    delay_us__

        0x08003b66:    e7f9        ..      B        Get_SysTimeMs__ ; 0x8003b5c

发送串口数据正常,

情况四

使用while循环,后面紧接着Get_SysTimeMs__和delay_us__函数,可以正常发送串口函数。

后面只紧接着delay_us__函数也可正常发送。因为delay_us__里面用了for循环。

// 简单的延时函数

void delay_us(uint32_t us) {

    while (us--) {

        __NOP();

    }

}

int cnt;

int Get_SysTimeMs__(){

    return cnt++;

}

int delay_us__(uint16_t us) {

    for(int i=0;i<us;i++)

    {}

}

对应汇编函数

delay_us

        0x08003b50:    e000        ..      B        0x8003b54 ; delay_us + 4

        0x08003b52:    bf00        ..      NOP      

        0x08003b54:    1e40        @.      SUBS     r0,r0,#1

        0x08003b56:    1c41        A.      ADDS     r1,r0,#1

        0x08003b58:    d1fb        ..      BNE      0x8003b52 ; delay_us + 2

        0x08003b5a:    4770        pG      BX       lr

    Get_SysTimeMs__

        0x08003b5c:    4a4c        LJ      LDR      r2,[pc,#304] ; [0x8003c90] = 0x200000b4

        0x08003b5e:    6810        .h      LDR      r0,[r2,#0]

        0x08003b60:    1c41        A.      ADDS     r1,r0,#1

        0x08003b62:    6011        .`      STR      r1,[r2,#0]

        0x08003b64:    4770        pG      BX       lr

    delay_us__

        0x08003b66:    2100        .!      MOVS     r1,#0

        0x08003b68:    e000        ..      B        0x8003b6c ; delay_us__ + 6

        0x08003b6a:    1c49        I.      ADDS     r1,r1,#1

        0x08003b6c:    4281        .B      CMP      r1,r0

        0x08003b6e:    dbfc        ..      BLT      0x8003b6a ; delay_us__ + 4

        0x08003b70:    4770        pG      BX       lr

也能正常发送串口数据,电脑接收到[19:42:11.328]收←◆Ahello02
中文

只记录了现象,为什么会这样,还不知道,总之使用循环的时候,特别是空循环的时候,要注意。

;