我正在开发一种直流电机的控制器。这台马达有一个编码器,根据它的运动产生脉冲。
我需要通过监测脉冲数来控制电机轴的圈数。
我在这个应用程序中使用SMT8S103F3。
这个想法是使用Timer1作为脉冲计数器。为此,我将定时器配置为接收外部信号,在本例中为编码器脉冲,并且随着每个脉冲,计数器必须递增。
我遵循了文档ST RM0016的第17.4.3章。但是,应用程序无法正常工作。计数器没有递增。
遵循开发的代码。
void config_counter(){
TIM1_PSCRH = 0;
TIM1_PSCRL = 0; //Prescalar 1 division
TIM1_ARRH = 0;
TIM1_ARRL = 0; //Auto counter disabled
TIM1_CNTRH = 0;
TIM1_CNTRL = 0; //Reset counter
TIM1_IER = 0; //Interrupt disabled
TIM1_SR1 = 0; //Clear Interrupt
TIM1_CCMR2 |= 1<<0; //External pulse source T1C2
TIM1_CCER1 |= ~(1<<5); //Rising edge
TIM1_SMCR |= 3; //T1C2 input
TIM1_CR1 |= ~(1<<0); //Counter disabled
return;
}
void set_counter_enable(uint8_t enable){
if(enable==1)
TIM1_CR1 |= 1<<0;
else
TIM1_CR1 |= ~(1<<0);
return;
}
void set_counter_updown(uint8_t updown){
if(updown==1)
TIM1_CR1 |= ~(1<<4);
else
TIM1_CR1 |= 1<<4;
return;
}
uint8_t start_movement_monitor(uint8_t dir){
while(1){
if(dir == 1){
if(((TIM1_CNTRH<<8)+TIM1_CNTRL)>200)
return 1;
}else if(dir == 2){
if(((TIM1_CNTRH<<8)+TIM1_CNTRL)<50)
return 1;
}
else{
return 1;
}
}
return 1;
}
int main() {
config_gpio();
config_counter();
set_counter_updown(0);
set_counter_enable(0);
set_counter_enable(1);
set_motor_enable(1);
set_motor_movement(1);
start_movement_monitor(1);
set_motor_movement(0);
set_motor_enable(0);
set_counter_enable(0);
return 0;
}有什么想法吗?
如果定时器不是此应用的最佳选择,如何实现脉冲计数器?
脉冲频率为700 The。
发布于 2021-01-07 03:24:35
解决了。
要在stm8引脚上使用定时器,必须写入选项字节以改变引脚的功能。这是通过编写AFR0实现的。
使用定时器1通道2的定时器配置如下。
void config_counter(){
TIM1_CNTRH = 0;
TIM1_CNTRL = 0; //Reset counter
TIM1_IER = 0; //Interrupt disabled
TIM1_SR1 = 0; //Clear Interrupt
TIM1_CCMR2 |= 1<<0; //External pulse source T1C2
TIM1_CCER1 &= ~(1<<5); //Rising edge
TIM1_SMCR |= (7<<0); //External Clock Source
TIM1_SMCR |= (6<<4); //T1C2 Input Source
TIM1_CR1 &= ~(1<<0); //Counter disabled
return;
}发布于 2021-01-06 06:36:42
TIM1_CR1 |= ~(1<<0); //Counter disabled不会禁用计数器。它保持CEN不变,并将包括OPM在内的所有其他位设置为1。您需要的是&=。set_counter_updown也是如此。
发布于 2021-01-06 09:45:35
这个问题有两种可能的解决方案。
定时器的解决方案要求定时器的时钟输入与电机脉冲关联,这需要一些外部硬件连接,我不知道您是否有可用的外部硬件连接。这样做的好处是,您可以只读取计时器值来了解圈数,并且使用预分频器可以缩放您的输入。缺点是定时器的数量通常是有限的(您只有一个或两个定时器),而且定时器总是配置为计算电机转数,并且您不能将其用于其他事情。
另一种解决方案是为电机脉冲关联一条中断线路,并对中断处理程序进行编程。您需要(通过硬件)将中断关联到电机脉冲,因此当您接收到中断时,中断处理程序会递增一个变量。
一旦你有了这个...你只需要检查变量的值是什么,因为变量的更新只是反映了电机转动了多少次。
volatile long loops = 0;
void motor_pulse_handler()
{
loops++;
}
int main()
{
/* this function installs the handler to be called each time the motor starts a new turn. */
install_handler(MOTOR_PULSE_INTERRUPT, motor_pulse_handler);
...
for (;;) {
printf("\rloops: %ld", loops);
usleep(10000);
}
} 函数install_handler是强烈依赖于硬件的函数。它通常由开发系统作为库函数提供,因为它需要了解一点处理器体系结构才能实现。在操作与中断相关的控件时,首先需要完全禁用中断。然后,它必须被激活,以便中央处理器在相应的中断线上的一个脉冲上被中断(这就是在参数列表中包括一个MOTOR_PULSE_INTERRUPT的原因,它应该是具有适当值的#defined,以使电机脉冲成为所选信号,而不是其它信号)。最后,它必须再次使能中断。当中断到来时,您的函数将在处理器可以执行的一系列操作的中间被调用。
通常,安装中断处理程序是一个两阶段的过程。实际调用的例程不是传递给install_handler的例程,而是执行一些硬件操作的不同例程。在禁止中断的情况下调用中断处理程序,它应该:
此解决方案的优点是您可以卸载信号处理程序,这将停止计数过程。同样,只有在实现某种机制来路由中断的情况下,才能将中断行重用于其他事情(此问题类似于计时器中的问题,其中脉冲到达所选计时器的输入)
https://stackoverflow.com/questions/65586571
复制相似问题