欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 创投人物 > STM32F4 超声波测距控制舵机控制

STM32F4 超声波测距控制舵机控制

2025/4/5 20:44:35 来源:https://blog.csdn.net/Cha3043445754/article/details/146996432  浏览:    关键词:STM32F4 超声波测距控制舵机控制

这次我们将实践定时器捕获和定时器比较输出PWM,完成超声波测距控制舵机控制

程序思路

超声波每100ms进行检测 (通过定时器7每一毫秒中断),如果检测的距离小于5cm ,我们就将舵机,进行比较寄存器加特定值,控制舵机转动。(定时器4中断服务函数)

首先我们将用到定时器TIM4,TIM7,TIM14 (由于IO口的复用),将TIM7做为定时中断(超声波多少秒进行检测),TIM4用与输入捕获用于捕获超声波反馈回来的脉冲,TIM14用于输出PWM控制舵机

主函数

int main(void){	NVIC_SetPriorityGrouping(5);	usart1_init(115200);	SR04_init();	tim14_ch1_pwm();	timer7_interrupt_ms_init(1);
	BEEP_ON;	delay_ms(300);	BEEP_OFF; 
	while(1)	{	}
	return  0;}

初始化函数

超声波初始化

void SR04_init(void){	tim4_ch1_input_init();	RCC->AHB1ENR |= (1<<1);	GPIOB->MODER &= ~(3<<16);	GPIOB->MODER |= (1<<16);	GPIOB->ODR &= ~(1<<8);}

超声波开始函数

void SR04_star(void){	GPIOB->ODR |= (1<<8);	timer6_delay_us(10);	GPIOB->ODR &= ~(1<<8);
}

定时器4通道捕获(初始化定时器输入捕获)

void tim4_ch1_input_init(void){	/*IO口控制器配置*/	//端口时钟使能	RCC->AHB1ENR |= (1<<1);	//端口模式配置	GPIOB->MODER &= ~(3<<12);	GPIOB->MODER |= (2<<12);	//上下拉配置	GPIOB->PUPDR &= ~(3<<12);	//复用功能配置	GPIOB->AFR[0] &= ~(0xf<<24);	GPIOB->AFR[0] |= (2<<24);
	/*定时器配置*/	//定时器时钟使能	RCC->APB1ENR |= (1<<2);	//CR1	TIM4->CR1 &= ~(3<<8);	TIM4->CR1 |= (1<<7);	TIM4->CR1 &= ~(3<<5);	TIM4->CR1 &= ~(1<<4);	TIM4->CR1 &= ~(1<<3);	TIM4->CR1 &= ~(1<<2);	TIM4->CR1 &= ~(1<<1);
	//SMCR	TIM4->SMCR &= ~(7<<0);
	//DIER	TIM4->DIER |= (1<<1);	TIM4->DIER |= (1<<0);
	//CCMRx	TIM4->CCMR1 &= ~(3<<0);	TIM4->CCMR1 |= (1<<0);	TIM4->CCMR1 &= ~(0xf<<4);	TIM4->CCMR1 |= (0xf<<4);
	//CCER	TIM4->CCER |= (1<<0);	TIM4->CCER &= ~(1<<1);	TIM4->CCER &= ~(1<<3);
	//PSC	TIM4->PSC = 84-1;	//ARR	TIM4->ARR = 65535;
	//EGR	TIM4->EGR |= (1<<0);	/*NVIC控制器配置*/	//优先级分组---------主函数	//计算优先级编码值	u32 pri = NVIC_EncodePriority (5,1,0);	//确定具体中断源	NVIC_SetPriority(TIM4_IRQn,pri);	//使能NVIC响应通道	NVIC_EnableIRQ(TIM4_IRQn);
	//使能计数器	TIM4->CR1 |= (1<<0);}

初始化定时器14输出比较(可以作为舵机初始化)

void tim14_ch1_pwm(void){	/*IO口控制器*/	//端口时钟使能	RCC->AHB1ENR |= (1<<0);	//端口模式配置-----复用输出	GPIOA->MODER &= ~(3<<14);	GPIOA->MODER |= (2<<14);	//输出类型	GPIOA->OTYPER &= ~(1<<7);	//输出速度	GPIOA->OSPEEDR &= ~(3<<14);	//上下拉配置	GPIOA->PUPDR &= ~(3<<14);	//复用功能寄存器	GPIOA->AFR[0] &= ~(0xf<<28);	GPIOA->AFR[0] |= (9<<28);
	/*定时器和通道配置*/	//定时器时钟使能	RCC->APB1ENR |= (1<<8);	//CR1	TIM14->CR1 |= (1<<7);     //重载影子寄存器	TIM14->CR1 &= ~(1<<1);    //产生更新事件的条件	//CCMRx	TIM14->CCMR1 &= ~(3<<0);  //将通道定位输出模式	TIM14->CCMR1 |= (1<<3);   //比较寄存器影子寄存器	TIM14->CCMR1 &= ~(7<<4); 	TIM14->CCMR1 |= (6<<4);   //PWM1
	//CCER	TIM14->CCER |= (1<<0);    //开启通道	TIM14->CCER &= ~(1<<1);    //高电平有效
	//PSC	TIM14->PSC = 84-1;
	//ARR	TIM14->ARR = 20000-1;
	//CCRx	TIM14->CCR1 = 500;
	//EGR	TIM14->EGR |= (1<<0);        //人为产生更新事件
	//计数器是能	TIM14->CR1 |= (1<<0); }

舵机初始化函数(直接调用定时器14的初始化,主函数没有调用是因为直接调用了tim14_ch1_pwm()初始化函数)

​​​​​​​

void sg90_init(void){	tim14_ch1_pwm();}



我们再初始化定时器7毫秒级定时中断(每几毫秒触发一次中断)

void timer7_interrupt_ms_init(u16 ms){	/*定时器控制器配置*/	//定时器时钟使能	RCC->APB1ENR |= (1<<5);	//CR1   (3号位要写0,连续计数; 2号位写0  可以产生中断)	TIM7->CR1 |= (1<<7);	TIM7->CR1 &= ~(1<<3);    //循环计数	TIM7->CR1 &= ~(1<<2);    //可以产生中断的条件	TIM7->CR1 &= ~(1<<1);    //可以产生更新事件的条件	//DIER中断使能	TIM7->DIER |= (1<<0);	//分频寄存器	TIM7->PSC = 8400-1;	//重载值寄存器	TIM7->ARR = ms * 10 -1;	//人为产生更新事件	TIM7->EGR |= (1<<0);	//清除中断标志位	TIM7->SR &= ~(1<<0);
	/*NVIC控制器配置*/	//优先级分组---------主函数	//计算优先级编码值	u32 pri = NVIC_EncodePriority (5,1,3);	//确定具体中断源	NVIC_SetPriority(TIM7_IRQn,pri);	//使能NVIC响应通道	NVIC_EnableIRQ(TIM7_IRQn);	//计数器使能	TIM7->CR1 |= (1<<0);
}

中断函数

定时器4中断服务函数(计数器更新中断信号和捕获寄存器捕获中断信号)

void TIM4_IRQHandler(void){	static u8 tim_n = 0;	static u16 test_1;	u16 test_2;	u32 test;	float cm_val;	static u8 servo_state = 0; // 新增:舵机状态标志(0:0度,1:180度)
	//判断更新中断标志Wie	if(TIM4->SR & (1<<0))	{		//清除标志位		TIM4->SR &= ~(1<<0);		//紧急事件		tim_n++;		}	//判断捕获中断标志位	if(TIM4->SR & (1<<1))	{		//清除标志位		TIM4->SR &= ~(1<<1);		//紧急事件		//如果是边沿1触发捕获 上升沿		if(!(TIM4->CCER & (1<<1)))		{			tim_n = 0;     //开始记录有效溢出次数			//记录捕获寄存器的第一次值			test_1 = TIM4->CCR1;			//切换边沿2			TIM4->CCER |= (1<<1);		}		//如果是边沿2触发捕获  下降沿		else if(TIM4->CCER & (1<<1))		{			//记录捕获寄存器的第二次值			test_2 = TIM4->CCR1;			//计算脉宽			test = tim_n*65535-test_1+test_2;			cm_val = test/1000.0 * 34 / 2;			if(cm_val <= 5 )			{
				if(servo_state == 0)                {                    TIM14->CCR1 = 2500; // 180度位置                    servo_state = 1;                }                else                {                    TIM14->CCR1 = 500;  // 0度位置                    servo_state = 0;                }			}
			printf("检测距离:%0.1fcm\r\n",cm_val);
			//再次切换边沿1			TIM4->CCER &= ~(1<<1);		}				
	}}

定时器7中断函数

u32 timer7_cont[10];void TIM7_IRQHandler(void){	//判断是TIM7的定时完成中断信号触发	if(TIM7->SR & (1<<0))	{		//清除标志Wie		TIM7->SR &= ~(1<<0);		//紧急事件		timer7_cont[1]++;				
			if(timer7_cont[1]>=100)		{			timer7_cont[3] = 0;
			SR04_star();		}	}}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词