项目 超声波自拍神器源码+讲解

源码:

链接: https://pan.baidu.com/s/17r1dJ3s21KfFIS3HOLDcLA?pwd=lolo 提取码: lolo 复制这段内容后打开百度网盘手机App,操作更方便哦
以下如果格式乱就打开【腾讯文档】超声波自拍神器项目
https://docs.qq.com/doc/DRkhDeXZ3QmJxRWVx

一、  main.c

主函数代码

int main(void)
{              
	SystemInit(); //系统时钟配置函数,选择外部8M晶振
  Nvic_Init(); //NVIC初始化	
  LED_Init(); //
	Key_Init();
	sleep_mode();
	//Timer1_Init(488,5);  //16526hz 
	//Timer1_Init(503,5);  //15870hz    拍照
	//Timer1_Init(511,5);  //15617hz
	//Timer1_Init(483,3);  //165260hz     切换摄像头
  while(1)
	{   
			GPIO_SetBits(LED_PORT ,GPIO_Pin_6);
		  delay_ms(250);
		  GPIO_ResetBits(LED_PORT ,GPIO_Pin_6);
		  delay_ms(250);
			if(flag)
			{
					flag = 0;
					PWR_EnterSleepMode(PWR_SLEEPEntry_WFI);
					
			}
			
  }									            	
}

1.  SystemInit(),是库自带的.

.知识点1:systick定时器

1.1概念

SysTick又称滴答定时器。是一个定时设备,位于Cortex-M0内核中,和NVIC捆绑(可以产生中断信号),产生SysTick异常(IRQ异常号15)可以对输入的时钟进行计数,系统定时器一般用于操作系统,用于产生时基,维持操作系统的心跳。(1ms)

1.2systick定时器普通定时器(TIM)区别

SysTick 计数器:

①用途用于生成系统时钟滴答信号从而提供精确时间延迟时间片管理

适用于需要高精度延迟的应用,但功能较为简单。

限制

功能相对简单,主要用于基本的时间延迟和中断生成。

没有像普通定时器那样的复杂功能,例如输入捕获、输出比较、PWM 输出等。

TIM定时器

用途

用于更复杂的定时和计时功能,如周期性中断、PWM 信号生成、输入捕获、输出比较等。

总结: 关于两者怎么选择,如果你的应用只需要简单的周期性中断和时间延迟,SysTick 计数器可能更直接和高效。对于更复杂的应用,特别是那些需要多通道和多模式的情况,TIM 定时器会更适合。

2.Nvic_Init

void Nvic_Init(void)
{ 
	
   NVIC_InitTypeDef  NVIC_InitStructure;
  
	
  /*1--串口中断管理*/
	//配置USART2中断
	 NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;  //中断通道  USART2_IRQn
   NVIC_InitStructure.NVIC_IRQChannelPriority = 0x00;  //中断优先级
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  //中断使能
   NVIC_Init(&NVIC_InitStructure);   //调用函数进行初始化   NVIC_Init()用于配置 NVIC 的中断通道  
	//配置KEY1中断
   NVIC_InitStructure.NVIC_IRQChannel = KEY1_BUTTON_EXTI_IRQn;//中断通道  KEY1_BUTTON_EXTI_IRQn
   NVIC_InitStructure.NVIC_IRQChannelPriority = 0x03;  //中断优先级
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  //中断使能
   NVIC_Init(&NVIC_InitStructure);
  
  // 可以继续增加,设置中断优先级

 
}

3.LED_Init

void LED_Init(void)
{
     GPIO_InitTypeDef        GPIO_InitStructure;
     
     /* GPIOE 外部时钟使能 */
     RCC_AHBPeriphClockCmd(LED_PORT_CLK, ENABLE);
	
     /* 配置 LED灯端口 外部输出上拉模式 */
     GPIO_InitStructure.GPIO_Pin   = LED_PIN | GPIO_Pin_6; //配置多个 GPIO 引脚
     GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_OUT;//设置引脚为输出模式。
     GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;  //设置输出为推挽模式。
     GPIO_InitStructure.GPIO_PuPd =  GPIO_PuPd_UP; //启用内部上拉电阻,用于在引脚未被主动驱动时保持稳定的高电平。这样可以确保引脚在空闲或不连接的情况下不会漂浮,防止噪声干扰或未定义状态。
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置 GPIO 输出速度为 50 MHz。
     GPIO_Init(LED_PORT , &GPIO_InitStructure); // 根据上述配置初始化 GPIO 端口。
	   
     //关闭LED
     GPIO_ResetBits(LED_PORT ,LED_PIN_1); // 将 LED 引脚的状态设置为低电平,从而关闭 LED。
	  

}

4.Key_Init

void Key_Init(void)    //初始化两个按键(KEY1 和 KEY2)的 GPIO 引脚及其外部中断功能
{
		//两个按键(KEY1 和 KEY2)的 GPIO 引脚
      GPIO_InitTypeDef GPIO_InitStructure;
      EXTI_InitTypeDef EXTI_InitStructure;
      
      /* 使能KEY按键对应GPIO的Clock时钟 */

      RCC_AHBPeriphClockCmd(KEY1_BUTTON_CLK , ENABLE); //使能连接到按键(KEY1)引脚的 GPIO 的时钟。
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);  //使能 SYSCFG 外设的时钟,用于配置外部中断。

      //用户按键配置--KEY1--PC13
      GPIO_InitStructure.GPIO_Pin =  KEY1_BUTTON_PIN ;  //指定要初始化的引脚
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;   //将引脚配置为输入模式。
      GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;   //不启用上拉或下拉电阻。
      GPIO_Init(KEY1_BUTTON_PORT , &GPIO_InitStructure); //将引脚配置为输入模式。
      
       //用户按键配置--KEY2引脚配置--PC12
      GPIO_InitStructure.GPIO_Pin =  KEY2_BUTTON_PIN ; //指定要初始化的引脚
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;   //将引脚配置为输入模式。
      GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;		//启用上拉电阻
      GPIO_Init(KEY1_BUTTON_PORT , &GPIO_InitStructure);  //将引脚配置为输入模式。
      
     //配置外部中断
      SYSCFG_EXTILineConfig(KEY_BUTTON_EXTI_PORT_SOURCE, KEY1_BUTTON_EXTI_PIN_SOURCE); //配置 KEY1 的 EXTI 线源。
      SYSCFG_EXTILineConfig(KEY_BUTTON_EXTI_PORT_SOURCE, KEY2_BUTTON_EXTI_PIN_SOURCE); //配置 KEY2 的 EXTI 线源。
     
      EXTI_InitStructure.EXTI_Line = KEY1_BUTTON_EXTI_LINE;  //PC13  选择外部中断线(KEY1 对应的线)。
      EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;    //设置为中断模式。
      EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;  //设置中断触发为上升沿。
      EXTI_InitStructure.EXTI_LineCmd = ENABLE;  //使能该中断线。
      EXTI_Init(&EXTI_InitStructure);  //应用上述配置。
			
			EXTI_InitStructure.EXTI_Line = KEY2_BUTTON_EXTI_LINE; //PC12
      EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
      EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;  
      EXTI_InitStructure.EXTI_LineCmd = ENABLE;
      EXTI_Init(&EXTI_InitStructure);
}

5.sleep_mode

void sleep_mode(void) //用于将微控制器置于低功耗模式。具体地,它使能了电源管理模块的时钟,并进入了休眠模式
{
		RCC_APB1PeriphClockCmd( RCC_APB1Periph_PWR  , ENABLE); //用于使能或禁用 APB1 总线上的外设时钟。在这里,它被用来使能电源管理外设的时钟 (RCC_APB1Periph_PWR),这是进入低功耗模式所必需的。ENABLE 参数表示我们要使能该外设的时钟。
	  PWR_EnterSleepMode(PWR_SLEEPEntry_WFI);//PWR_EnterSleepMode 函数用于将微控制器置于休眠模式。在休眠模式下,CPU 会停止执行指令,除非有外部中断或者其他唤醒事件发生。PWR_SLEEPEntry_WFI 参数指定使用 "Wait For Interrupt"(等待中断)方式进入休眠模式。即 CPU 会等待一个中断事件来唤醒。
}

配置电源管理模块(PWR)需要通过 RCC 模块进行,而 RCC 模块的配置和操作涉及到 APB1 总线,所以用到APB1

6.变量

unsigned short int systick_num=0x00; //systick计数器变量
unsigned short int key_num=0x00; //按键计数器变量
unsigned char Uart_buf[2]={0x00,0x00}; //缓冲接收缓冲器
unsigned char flag=0;

7. delay_ms(

void delay_ms(unsigned char a)
{
		unsigned int i,j;
	  
	  while(a--)
		{
			for(i=0;i<100;i++)
			 for(j=0;j<95;j++);
		}	
}

分析:

for(j=0;j<95;j++); 95指令周期

for(i=0;i<100;i++) 100*95= 9500个指令周期

while(a--) 9500指令周期

因此延迟时间9500 * a 指令周期

例如假设处理器时钟频率16MHZ

那么每个指令周期时间1/16000000 = 62.5纳秒

Delay (秒) = (9500 * a) * 62.5e-9

≈ 0.00059375 * a

≈ 0.594 ms * a

在科学记数法中,e-9 是为了简化表示非常小的数值(如纳秒级别的时间)

void sleep_mode(void) //用于将微控制器置于低功耗模式。具体地,它使能了电源管理模块的时钟,并进入了休眠模式
{
		RCC_APB1PeriphClockCmd( RCC_APB1Periph_PWR  , ENABLE); //用于使能或禁用 APB1 总线上的外设时钟。在这里,它被用来使能电源管理外设的时钟 (RCC_APB1Periph_PWR),这是进入低功耗模式所必需的。ENABLE 参数表示我们要使能该外设的时钟。
	  PWR_EnterSleepMode(PWR_SLEEPEntry_WFI);//PWR_EnterSleepMode 函数用于将微控制器置于休眠模式。在休眠模式下,CPU 会停止执行指令,除非有外部中断或者其他唤醒事件发生。PWR_SLEEPEntry_WFI 参数指定使用 "Wait For Interrupt"(等待中断)方式进入休眠模式。即 CPU 会等待一个中断事件来唤醒。
}
配置电源管理模块(PWR)需要通过 RCC 模块进行,而 RCC 模块的配置和操作涉及到 APB1 总线,所以用到APB1

8.  Timer1_Init

void Timer1_Init(unsigned short int arr,unsigned short int psc)
{    
        
        TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;	// 配置定时器的基本时间基准
        TIM_OCInitTypeDef TIM_OCInitStructure;  // 配置输出比较(OC)模式的参数
        TIM_BDTRInitTypeDef TIM_BDTRInitStructure;  // 配置定时器的死区时间和主从模式
    
        PWM_GPIO_Init(); // 初始化 PWM 所用的 GPIO 端口
        RCC_APB2PeriphClockCmd(F072B_TIMER_CLK , ENABLE);   // 使能定时器1的时钟,以确保定时器正常工作
        //TIM_DeInit(F072B_TIMER_PWM); // 可选:重置定时器设置
        
        // 设置定时器相关参数
        TIM_TimeBaseInitStructure.TIM_Prescaler = psc;  // 设置定时器的预分频器值,调整定时器的计数频率
        TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; // 设置定时器为向上计数模式
        TIM_TimeBaseInitStructure.TIM_Period = arr ;  // 设置定时器的自动重装载寄存器周期值
        TIM_TimeBaseInitStructure.TIM_ClockDivision = 0; // 设置时钟分频系数为 0,即不分频
        TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; // 设置重复计数器的值,0 表示没有重复计数
        TIM_TimeBaseInit(F072B_TIMER_PWM, &TIM_TimeBaseInitStructure);  // 初始化定时器基础设置
    
        // PWM 模式设置 - CH1
        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // 设置定时器通道为 PWM 模式 1
        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 启用输出
        TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; // 启用互补输出
        TIM_OCInitStructure.TIM_Pulse = 240; // 设置 PWM 的占空比
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; // 设置 PWM 输出的极性为低
        TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCPolarity_High; // 设置互补输出的极性为高
        TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set; // 设置定时器在空闲状态时输出状态
        TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset; // 设置互补输出在空闲状态时的输出状态
        TIM_OC1Init(F072B_TIMER_PWM, &TIM_OCInitStructure); // 初始化定时器通道 1 的输出比较设置
    
        TIM_OC1PreloadConfig(F072B_TIMER_PWM, TIM_OCPreload_Enable); // 启用通道 1 的预装载功能
    
        //TIM_ARRPreloadConfig(F072B_TIMER_PWM, ENABLE); // 可选:启用自动重装载预装载功能
        TIM_Cmd(F072B_TIMER_PWM, ENABLE); // 启动定时器,使其开始计数
        TIM_CtrlPWMOutputs(F072B_TIMER_PWM, ENABLE); // 启用定时器的 PWM 输出功能
}

8.  PWM_GPIO_Init

void PWM_GPIO_Init(void)
{
     GPIO_InitTypeDef GPIO_InitStructure;  // 声明一个 GPIO 初始化结构体变量

     // 时钟配置
     RCC_AHBPeriphClockCmd(F072B_PWM_CH_CLK|F072B_PWM_CHN_CLK , ENABLE);   // 使能 GPIOA/GPIOB 端口的时钟

     // GPIOA 通道配置 : TIM1 CH1 (PA8)/TIM1 CH2 (PA9) /TIM1 CH3 (PA10)*/
     GPIO_InitStructure.GPIO_Pin =   F072B_PWM_CH1_PIN|F072B_PWM_CH2_PIN|F072B_PWM_CH3_PIN;  // 配置要初始化的引脚
     GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_AF;  // 设置 GPIO 引脚为复用功能模式
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  // 设置引脚的速率为 50MHz
     GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;  // 设置输出类型为推挽输出
     GPIO_InitStructure.GPIO_PuPd =  GPIO_PuPd_UP ;  // 设置引脚为上拉电阻
     GPIO_Init(F072B_PWM_CH_P0RT , &GPIO_InitStructure);  // 初始化 GPIO 端口

     // GPIOB 通道配置 : TIM1 CH1N (PB13)/TIM1 CH2N (PB14) /TIM1 CH3N (PB15)*/
     GPIO_InitStructure.GPIO_Pin =   F072B_PWM_CH1N_PIN|F072B_PWM_CH2N_PIN|F072B_PWM_CH3N_PIN;  // 配置另一组要初始化的引脚
     GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_AF;  // 设置 GPIO 引脚为复用功能模式
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  // 设置引脚的速率为 50MHz
     GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;  // 设置输出类型为推挽输出
     GPIO_InitStructure.GPIO_PuPd =  GPIO_PuPd_UP ;  // 设置引脚为上拉电阻
     GPIO_Init(F072B_PWM_CHN_P0RT , &GPIO_InitStructure);  // 初始化 GPIO 端口

     // 端口复用功能配置
     GPIO_PinAFConfig(F072B_PWM_CH_P0RT,    F072B_PWM_CH1_SOURCE,  F072B_PWM_CH1_AF);  // 配置 PA8 为 TIM1 CH1 的复用功能
     GPIO_PinAFConfig(F072B_PWM_CH_P0RT ,   F072B_PWM_CH2_SOURCE,  F072B_PWM_CH2_AF);  // 配置 PA9 为 TIM1 CH2 的复用功能
     GPIO_PinAFConfig(F072B_PWM_CH_P0RT ,   F072B_PWM_CH3_SOURCE,  F072B_PWM_CH3_AF);  // 配置 PA10 为 TIM1 CH3 的复用功能
     GPIO_PinAFConfig(F072B_PWM_CHN_P0RT ,  F072B_PWM_CH1N_SOURCE, F072B_PWM_CH1N_AF);  // 配置 PB13 为 TIM1 CH1N 的复用功能
     GPIO_PinAFConfig(F072B_PWM_CHN_P0RT ,  F072B_PWM_CH2N_SOURCE, F072B_PWM_CH2N_AF);  // 配置 PB14 为 TIM1 CH2N 的复用功能
     GPIO_PinAFConfig(F072B_PWM_CHN_P0RT ,  F072B_PWM_CH3N_SOURCE, F072B_PWM_CH3N_AF);  // 配置 PB15 为 TIM1 CH3N 的复用功能
}

知识点2: 什么是输出比较?

输出比较(Output Compare) 是定时器的一种模式,主要用于生成精确的定时事件和脉冲。在这种模式下,定时器的计数值与预设的比较值(比较寄存器中的值)进行比较,当计数值与比较值相等时,定时器会产生一个事件或改变输出端口的状态。这通常用于生成 PWM 信号、定时中断、或控制信号的脉冲宽度。

也就是说定时器计数值等于比较就会产生PWM信号知识点3:分频系数和预分频值的区别?

预分频器(Prescaler):预分频器是定时器的配置参数,用于将定时器时钟的频率降低到所需的计数频率。比如,如果系统时钟为 48 MHz,通过设置预分频器为 4799,可以将计数频率降低到 10 kHz(即 48 MHz / (4799 + 1))。

时钟分频系数(Clock Division):这是一个定时器的附加参数,用于对定时器的时钟进行进一步的分频处理。在一些高级定时器中,时钟分频系数可以控制定时器内部的时钟信号的分频。通常情况下,预分频器和时钟分频系数是两个不同的配置,预分频器影响的是计数器的时钟频率,而时钟分频系数影响的是定时器的时钟源分频。

知识点4:什么是重复计数器

复计数器 是高级定时器(例如 STM32 的高级定时器)中一个特殊的功能,用于配置定时器的重复模式。它可以用来生成重复的 PWM 信号或多个 PWM 周期

功能:重复计数器设置了定时器在每个计数周期结束后重复执行的次数。例如,如果设置为 1,则定时器会每个计数周期重复一次。如果设置为 0,则定时器不会重复。

应用:在需要生成复杂的 PWM 波形或在高级定时器中生成多个频率不同的信号时,重复计数器非常有用。

如果重复计数器设置为2,则定时器会在每个完整周期后重复触发两次中断

知识点5什么是 PWM 输出极性(PWM Output Polarity)?

PWM 输出极性 定义了 PWM 信号的逻辑状态,即信号的高电平和低电平的定义:

TIM_OCPolarity_Low:表示 PWM 信号的高电平对应的输出为低电平,低电平对应的输出为高电平。通常用于直接驱动负载。

TIM_OCPolarity_High:表示 PWM 信号的高电平对应的输出为高电平,低电平对应的输出为低电平。适用于需要正向驱动的应用。

知识点6: 什么是 PWM 输出空闲状态(PWM Output Idle State)?

PWM 输出空闲状态 定义了在 PWM 信号不活动时输出端口的状态:

TIM_OCIdleState_Set:在 PWM 信号为空闲状态时,将输出端口设置为设定状态(如高电平或低电平),通常用于防止在 PWM 信号停止时产生浮动信号。

TIM_OCIdleState_Reset:在 PWM 信号为空闲状态时,将输出端口设置为复位状态(通常是低电平),有助于保持信号的稳定性。

STM32 NUCLEO-F072RB开发方案设计——超声波自拍神器 对于从来没有玩过安卓系统的同学们是不是很想也体会到安卓给我们带来的乐趣了,那是不是没学安卓,就不能控制手机呢?就不能体会到安卓给我们带来的乐趣呢?除了蓝牙和wifi等外,我们还能不能有一种更简单的、更有创意的、更实用的方案,让大部分电子爱好者体会用STM32控制手机的乐趣了,答案是肯定的。 某宝上很多自拍神器,有蓝牙控制和线控等,这一次我将向大家介绍一种最近比较流行的超声波自拍神器,方便实用,成本低。 1.方案介绍: 首先手机先到网上下载一个APP(Airshooting),然后打开APP,利用STM32 NUCLEO-F072RB开发板的定时器产生一定频率PWM信号,用来控制蜂鸣器发出声音,当手机接收到蜂鸣器发出的声音后,会执行拍张操作,如果你的手机有前摄像头,还可以控制手机执行切换摄像头操作。 2.工作原理: 本设计主要重点是要调节PWM的频率。 (1)拍照的PWM频率为:先发送250ms的频率为15870Hz的PWM信号(占空比没什么要求,50%左右即可);后发送250ms的频率为15617Hz的PWM信号。这个频率精确度越高,控制的距离就越远。下图是我实际测量的频率,由于逻辑分析仪比较差,测量难免有误差。 (2)切换的PWM频率为:先发送250ms的频率为16526Hz的PWM信号(占空比没什么要求,50%左右即可);后发送250ms的频率为15620Hz的PWM信号。 只要让STM32开发板发出如上的PWM信号,控制蜂鸣器发声,那么手机就能接收到信号,执行拍照和切换镜头操作。 3.原理图 这个设计的原理图相当简单,学过单片机都用过,只需要一个简单的蜂鸣器电路即可,由于比较简单,我就用面包板搭建了。电路图如下: 除了以上电路,还用到了STM32 NULCEO-F072RB上的用户按键和LD2。 功能介绍: 考虑到本设计要作为手持设备,因此设置了上电后,板子进入睡眠模式,此时板子功耗低,节约电量。打开手机APP,按下板子上的用户按键,LD2点亮0.5s后熄灭,2s左右后,手机执行拍张功能;按下S1按键,LD2点亮0.5s后熄灭,2s左右后,手机执行切换镜头功能; 4.源代码 见附件 5..实物图 由于电路比较简单,就直接用面包板了,献丑了 实际测试发现,在空旷的地方,最远传输距离3M左右。调节PWM的精确度和增大蜂鸣器的功率,传输距离变远,由于最近比较忙,就没再调试下去了.......... 6.运行视频 7.注意事项 这里由于需要比较精准的PWM,因此我在开发板上焊接了一个8MHz的外部晶振和两个22PF的瓷片电容。 蜂鸣器我使用的是3V蜂鸣器,用5V蜂鸣器传输距离会比较近。 以上是我的参赛方案,虽然比较简单,淘宝上也有卖,但是我还没发现哪个网站有介绍我这个作品的,算是首创吧..........或许是因为我是个学渣,没发现吧,大牛勿喷哈.........
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值