你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

小白求助,结束while循环后会跳转至循环前继续执行的问题?

[复制链接]
神游戏 提问时间:2024-3-22 09:36 / 已解决

问题如题,原本是使用计时器输入捕获功能获取脉冲数的问题,后将代码修改如下使其仅仅只是计数输出一下0至10000的数字:






 int main(void)
 {
        u16 i = 0, j;
         LED_Init();                             //LED端口初始化
        uart_init(115200);

        printf("%d\r\n", 70000);  //串口输出程序启动标志


  while(1)
        {

                printf("%d\r\n", i++);
                if(i >= 10000) break;
        }

        LED0 = 0;
        printf("%d, %d\r\n", i, j);
 }

在上位机中根据输出数字显示波形,其波形如下:

屏幕截图2024-03-22130321.png

在跳出while循环后其会跳转至循环前继续执行两次,最终在第三次正常结束。

本人才疏学浅,初次遇到这种情况,真诚求助orz!

以下为原问题,目前来看可以暂时排除计时器的原因。


问题如题,电机的AB相分别连接TIM3的通道1和通道2,主函数代码如下:

/************************************************
        通过输入捕获获取有刷直流电机的脉冲数
************************************************/


 int main(void)
 {
        u16 i = 0, j;
         LED_Init();
        uart_init(115200);
        TIM3_Encoder_Init(65535, 0);

        printf("%d, %d\r\n", 70000, 0);  //串口输出程序启动标志

        while(i < 10000)  //i为累计检测到的脉冲数,如果累计检测到了10000个脉冲就结束循环
        {
                j = getEncoder();  //getEncoder()返回本次循环的脉冲数,返回后会将CNT置零
                printf("%d, %d\r\n", i, j);  //向串口1输出 累计的脉冲数 和 本次循环获取的脉冲数
                if(j < 100) i += j;  //排除可能存在的错误值后将脉冲数累计
        }

        LED0 = 0;
        printf("%d, %d\r\n", i, j);
 }

同时使用上位机观察串口输出的波形,理论上输出累积至10000以上就会结束,可实际输出波形如下:

屏幕截图2024-03-22124711.png

经多次测试,在累计脉冲数第一次和第二次接近循环判断值时程序会重启并重新计数,至第三次才会正常的结束这个计数过程。

输入捕获部分代码如下:

//arr:自动重装值,测试中使用65535
//psc:时钟预分频数,测试中使用0
void TIM3_Encoder_Init(u16 arr,u16 psc)
{  
        GPIO_InitTypeDef GPIO_InitStructure;
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        TIM_ICInitTypeDef  TIM_ICInitStructure;

        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
         RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
        GPIO_ResetBits(GPIOA, GPIO_Pin_6 | GPIO_Pin_7);

        TIM_TimeBaseStructure.TIM_Period = arr; 
        TIM_TimeBaseStructure.TIM_Prescaler = psc; 
        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 
        TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); 

        TIM_ICStructInit(&TIM_ICInitStructure);
        TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
        TIM_ICInitStructure.TIM_ICFilter = 0x0A;
        TIM_ICInit(TIM3, &TIM_ICInitStructure);
        TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
        TIM_ICInit(TIM3, &TIM_ICInitStructure);

        TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);


        TIM_Cmd(TIM3, ENABLE);

}

//获取当前脉冲数,获取后置0
u16 getEncoder()
{
        u16 temp;
        temp = TIM_GetCounter(TIM3);
        TIM_SetCounter(TIM3, 0);
        return temp;
}

本人纯纯清澈愚蠢大学生一枚,真诚求助orz!

屏幕截图 2024-03-22 092511.png
屏幕截图 2024-03-22 092511.png
收藏 评论8 发布时间:2024-3-22 09:36

举报

8个回答
落花又见流水 最优答案 回答时间:2024-3-22 18:00:07

兄弟啊,你这while循环要死循环才行啊,要不然都不知道运行到哪里去了。

image.png

image.png

xmshao 回答时间:2024-3-22 19:31:07
落花又见流水 发表于 2024-3-22 18:00
[md]兄弟啊,你这while循环要死循环才行啊,要不然都不知道运行到哪里去了。



呵呵还真是没见while(1)
xmshao 回答时间:2024-3-22 14:25:11
如果说是系统发生了复位,建议检查下基本的硬件线路。


找个简单的ST例程跑跑,看看到底是硬件方面还是软件方面的原因。


顺便提醒下,编码器的计数方向即向上计数还是向下计数,是由你的TI1 TI2输入波形的相对时序决定的。


这里有个关于STM32定时器编码器应用演示你可以参考下。基于编码器信号的PWM输出示例
xmshao 回答时间:2024-3-22 10:50:11
刚才拜读了你的部分代码,标题写的异常重启,给人感觉是系统重启了。


但从你具体描述来看,好像是在说计数器重启了,这跟系统重启是两码事。
计数器溢出发生重装是正常的。


你主循环里对计数个数进行累计,在通过getEncoder()函数获取计数值
时,并对TIM3的counter清0,又重新开始计数。


如果说你那个while判断循环体执行时间肯定不会超过oxffff个计数脉冲所对应的时间的话,
除了第一个初始读数值外,其它时候读到的数据应该是基本一样的,因为你每次读后都清零了。


如果说那个while判断循环体执行时间有可能超过oxffff个计数脉冲所对应的时间的话,那每次
读到的数据就是波动的,如果不考虑了溢出,计数偏差可能比较大,要看具体情况。


不太清楚你具体的应用目的,你在每次测试前在那个while判断循环之前加一句TIM_SetCounter(TIM3, 0);会怎样?
神游戏 回答时间:2024-3-22 12:38:13

xmshao 发表于 2024-3-22 10:50
刚才拜读了你的部分代码,标题写的异常重启,给人感觉是系统重启了。</p>
<p>

感谢大佬的回复orz。

关于重启的情况,是因为我在每次进入循环获取脉冲数之前会先向串口输出一个很高的数据使其在波形图中形成一个峰值来表示开始获取脉冲,这个串口输出在进入循环之前:printf("%d, %d\r\n", 70000, 0); //串口输出程序启动标志,本人也是初识嵌入式开发以我浅薄的认识来看似乎只有按下RESET键重新执行程序才可能再次输出这个数据,如果表述不清导致误解请原谅orz。

关于while判断循环体执行时间的情况,依我所见的话是不会超出oxffff个计数脉冲所对应的时间的,如您所说每次读取的数据也是几乎一样的,如主题附图中绿线所示,波动范围很小,之所以存在波动范围是因为尚未添加电机的驱动,每次测试都是手拧(毕竟只是为了数脉冲数)。

这个程序的目的是仅仅是为了测试有刷直流电机的使用,通过判断编码器发出的脉冲数量来控制电机的圈数,可是在判断编码器脉冲数量这一步就出现解决不了的问题了orz。

大佬的建议我尝试了一下,并没有发生什么变化orz。

不过还是感谢大佬的留言,期待您更多的回复。

神游戏 回答时间:2024-3-22 13:19:14

xmshao 发表于 2024-3-22 10:50
刚才拜读了你的部分代码,标题写的异常重启,给人感觉是系统重启了。</p>
<p>

大佬我发现了一个恐怖的情况啊,我在main中把计时器相关的部分删掉后仅仅只是向串口输出数字结果还是有重复执行的bug啊orz,原问题已修改您看这个还能解决吗。

神游戏 回答时间:2024-3-22 14:48:41

xmshao 发表于 2024-3-22 14:25
如果说是系统发生了复位,建议检查下基本的硬件线路。</p>
<p>

感谢大佬的回复,经测试无论是什么项目只要main函数执行完毕系统就会自动重启,重启次数各个项目并不相同。

本人初次接触嵌入式开发,目前暂不确定这个现象到底是硬件的问题还是STM32F1的机制,暂时通过在main函数的结尾增加死循环来确保系统不会重启,具体的情况我接下来会与正点原子的客服进行沟通尝试搞清楚。

感谢大佬提供的思路和学习资料,该问题暂时得到解决,真心感谢orz。

神游戏 回答时间:2024-3-23 11:42:40

落花又见流水 发表于 2024-3-22 18:00
兄弟啊,你这while循环要死循环才行啊,要不然都不知道运行到哪里去了。</p>
<p>

感谢大佬的回复,本人初次接触嵌入式开发,对于这些基础仍需要查漏补缺orz。

衷心感谢指点!

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版