编译对空循环的处理,会影响堵塞延时效果,具体怎么处理的还不知道,只知道结果和现象。
模拟串口输出字符,用到延时函数,同样的延时函数,会有正常和不正常输出的情况;具体现象如下,
//这部分函数是可以正常输出串口数据的
//使用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
中文
只记录了现象,为什么会这样,还不知道,总之使用循环的时候,特别是空循环的时候,要注意。