【江科大--32课程中讲解到的外部设备】

一、传感器模块(GPIO模块)

1.基本介绍

传感器模块:传感器元件(光敏电阻/热敏电阻/红外接收管等)的电阻会随外界模拟量的变化而变化,通过与定值电阻分压即可得到模拟电压输出,再通过电压比较器进行二值化即可得到数字电压输出

2.模块分析

当N1的阻值变小时,下拉作用就会增强,中间的AO端的电压就会拉低。极端情况下,N1阻值为0,AO输出被完全下拉,输出0V。

当N1的阻值变大时,下拉作用会减弱,中间的引脚由于R1的上拉作用,电压会升高。

3.LM393电压比较器

4.光敏传感器控制蜂鸣器

/*** 函    数:获取当前光敏传感器输出的高低电平* 参    数:无* 返 回 值:光敏传感器输出的高低电平,范围:0/1*/
uint8_t LightSensor_Get(void)
{return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);			//返回PB13输入寄存器的状态
}
/*** 函    数:蜂鸣器开启* 参    数:无* 返 回 值:无*/
void Buzzer_ON(void)
{GPIO_ResetBits(GPIOB, GPIO_Pin_12);		//设置PB12引脚为低电平
}/*** 函    数:蜂鸣器关闭* 参    数:无* 返 回 值:无*/
void Buzzer_OFF(void)
{GPIO_SetBits(GPIOB, GPIO_Pin_12);		//设置PB12引脚为高电平
}/*** 函    数:蜂鸣器状态翻转* 参    数:无* 返 回 值:无*/
void Buzzer_Turn(void)
{if (GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_12) == 0)		//获取输出寄存器的状态,如果当前引脚输出低电平{GPIO_SetBits(GPIOB, GPIO_Pin_12);						//则设置PB12引脚为高电平}else														//否则,即当前引脚输出高电平{GPIO_ResetBits(GPIOB, GPIO_Pin_12);						//则设置PB12引脚为低电平}
}
int main(void)
{/*模块初始化*/Buzzer_Init();			//蜂鸣器初始化LightSensor_Init();		//光敏传感器初始化while (1){if (LightSensor_Get() == 1)		//如果当前光敏输出1{Buzzer_ON();				//蜂鸣器开启}else							//否则{Buzzer_OFF();				//蜂鸣器关闭}}
}

5.对射式红外传感器计次

 当对红外传感器进行遮挡时,板载的led会熄灭,就 会触发电平引脚的高低电平的转换,就会触发相关的中断,对计数值进行++

1.基本流程

EXTI和NVIC不用手动的开启时钟

2.代码编写

1)NVIC例程部分在misc.c文件中【因为NVIC属于Cortex-M3的内部外设】

2)NVIC分组整个程序中只能有一次,如果怕重复定义,则直接写在主函数中

3)进入中断后,记得在最后要清除中断,要不然会一直在中断中【EXTI_ClearITPendingBit】

4)当我们把引脚设置为下降沿触发的时候,挡光片移开的时候数值加1

      当我们把引脚设置为上升沿触发的时候,挡光片挡住的时候数值加1

初始化
/*** 函    数:计数传感器初始化* 参    数:无* 返 回 值:无*/
void CountSensor_Init(void)
{/*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);		//开启GPIOB的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);		//开启AFIO的时钟,外部中断必须开启AFIO的时钟/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);						//将PB14引脚初始化为上拉输入/*AFIO选择中断引脚*/GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);//将外部中断的14号线映射到GPIOB,即选择PB14为外部中断引脚/*EXTI初始化*/EXTI_InitTypeDef EXTI_InitStructure;						//定义结构体变量EXTI_InitStructure.EXTI_Line = EXTI_Line14;					//选择配置外部中断的14号线EXTI_InitStructure.EXTI_LineCmd = ENABLE;					//指定外部中断线使能EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;			//指定外部中断线为中断模式EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;		//指定外部中断线为下降沿触发EXTI_Init(&EXTI_InitStructure);								//将结构体变量交给EXTI_Init,配置EXTI外设/*NVIC中断分组*/NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);				//配置NVIC为分组2//即抢占优先级范围:0~3,响应优先级范围:0~3//此分组配置在整个工程中仅需调用一次//若有多个中断,可以把此代码放在main函数内,while循环之前//若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置/*NVIC配置*/NVIC_InitTypeDef NVIC_InitStructure;						//定义结构体变量NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;		//选择配置NVIC的EXTI15_10线NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//指定NVIC线路使能NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;	//指定NVIC线路的抢占优先级为1NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			//指定NVIC线路的响应优先级为1NVIC_Init(&NVIC_InitStructure);								//将结构体变量交给NVIC_Init,配置NVIC外设
}
中断函数编写
/*** 函    数:EXTI15_10外部中断函数【去startup_stm32f10x_md.s】* 参    数:无* 返 回 值:无* 注意事项:此函数为中断函数,无需调用,中断触发后自动执行*           函数名为预留的指定名称,可以从启动文件复制*           请确保函数名正确,不能有任何差异,否则中断函数将不能进入*/
void EXTI15_10_IRQHandler(void)
{if (EXTI_GetITStatus(EXTI_Line14) == SET)		//判断是否是外部中断14号线触发的中断{/*如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动*/if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0){CountSensor_Count ++;					//计数值自增一次}EXTI_ClearITPendingBit(EXTI_Line14);		//清除外部中断14号线的中断标志位//中断标志位必须清除//否则中断将连续不断地触发,导致主程序卡死}
}
返回个数
/*** 函    数:获取计数传感器的计数值* 参    数:无* 返 回 值:计数值,范围:0~65535*/
uint16_t CountSensor_Get(void)
{return CountSensor_Count;
}
主函数调用
int main(void)
{/*模块初始化*/OLED_Init();			//OLED初始化CountSensor_Init();		//计数传感器初始化/*显示静态字符串*/OLED_ShowString(1, 1, "Count:");	//1行1列显示字符串Count:while (1){OLED_ShowNum(1, 7, CountSensor_Get(), 5);		//OLED不断刷新显示CountSensor_Get的返回值}
}

二、旋转编码器(EXTI模块)

1.基本介绍

旋转编码器:用来测量位置、速度或旋转方向的装置,当其旋转轴旋转时,其输出端可以输出与旋转速度和方向对应的方波信号,读取方波信号的频率和相位信息即可得知旋转轴的速度和方向

类型:机械触点式/霍尔传感器式/光栅式

有脉冲过来,STM32进入中断函数处理;没有脉冲,就做自己的事情。

旋转编码器工作原理图_编码器工作原理图解-腾讯云开发者社区-腾讯云

2.光栅式

3.霍尔传感器(适用于电机)

磁铁旋转时,通过霍尔传感器,就可以输出正交的方波信号。

 

4.机械触点式(适用于音量调节)

5.硬件电路

6.旋转编码器计次

1.基本流程

把一相的下降沿作为触发中断,在中断时刻读取另外一相的电平

但是上面的设计还是存在问题:当正转的时候,由于A相先出现下降沿,所以刚开始动就进入中断。反转是A相后出现下降沿,所以当转到位了,才进入中断

所以我们采用另外的方式:

A,B相都触发中断,只有B相下降沿和A相低电平的时候,才会正转,在A相下降沿和B相低电平时,才判断为反转

2.代码编写

初始化
/*** 函    数:旋转编码器初始化* 参    数:无* 返 回 值:无*/
void Encoder_Init(void)
{/*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);		//开启GPIOB的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);		//开启AFIO的时钟,外部中断必须开启AFIO的时钟/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);						//将PB0和PB1引脚初始化为上拉输入/*AFIO选择中断引脚*/GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);//将外部中断的0号线映射到GPIOB,即选择PB0为外部中断引脚GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);//将外部中断的1号线映射到GPIOB,即选择PB1为外部中断引脚/*EXTI初始化*/EXTI_InitTypeDef EXTI_InitStructure;						//定义结构体变量EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1;		//选择配置外部中断的0号线和1号线EXTI_InitStructure.EXTI_LineCmd = ENABLE;					//指定外部中断线使能EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;			//指定外部中断线为中断模式EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;		//指定外部中断线为下降沿触发EXTI_Init(&EXTI_InitStructure);								//将结构体变量交给EXTI_Init,配置EXTI外设/*NVIC中断分组*/NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);				//配置NVIC为分组2//即抢占优先级范围:0~3,响应优先级范围:0~3//此分组配置在整个工程中仅需调用一次//若有多个中断,可以把此代码放在main函数内,while循环之前//若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置/*NVIC配置*/NVIC_InitTypeDef NVIC_InitStructure;						//定义结构体变量NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;			//选择配置NVIC的EXTI0线NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//指定NVIC线路使能NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;	//指定NVIC线路的抢占优先级为1NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			//指定NVIC线路的响应优先级为1NVIC_Init(&NVIC_InitStructure);								//将结构体变量交给NVIC_Init,配置NVIC外设NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;			//选择配置NVIC的EXTI1线NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//指定NVIC线路使能NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;	//指定NVIC线路的抢占优先级为1NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;			//指定NVIC线路的响应优先级为2NVIC_Init(&NVIC_InitStructure);								//将结构体变量交给NVIC_Init,配置NVIC外设
}
2个中断处理函数

如果是两个中断使用同一个中断处理函数,则我们将两个if写在一个函数中 

int16_t Encoder_Count;					//全局变量,用于计数旋转编码器的增量值/*** 函    数:EXTI0外部中断函数* 参    数:无* 返 回 值:无* 注意事项:此函数为中断函数,无需调用,中断触发后自动执行*           函数名为预留的指定名称,可以从启动文件复制*           请确保函数名正确,不能有任何差异,否则中断函数将不能进入*/
void EXTI0_IRQHandler(void)
{if (EXTI_GetITStatus(EXTI_Line0) == SET)		//判断是否是外部中断0号线触发的中断{/*如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动*/if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0){if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)		//PB0的下降沿触发中断,此时检测另一相PB1的电平,目的是判断旋转方向{Encoder_Count --;					//此方向定义为反转,计数变量自减}}EXTI_ClearITPendingBit(EXTI_Line0);			//清除外部中断0号线的中断标志位//中断标志位必须清除//否则中断将连续不断地触发,导致主程序卡死}
}/*** 函    数:EXTI1外部中断函数* 参    数:无* 返 回 值:无* 注意事项:此函数为中断函数,无需调用,中断触发后自动执行*           函数名为预留的指定名称,可以从启动文件复制*           请确保函数名正确,不能有任何差异,否则中断函数将不能进入*/
void EXTI1_IRQHandler(void)
{if (EXTI_GetITStatus(EXTI_Line1) == SET)		//判断是否是外部中断1号线触发的中断{/*如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动*/if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0){if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)		//PB1的下降沿触发中断,此时检测另一相PB0的电平,目的是判断旋转方向{Encoder_Count ++;					//此方向定义为正转,计数变量自增}}EXTI_ClearITPendingBit(EXTI_Line1);			//清除外部中断1号线的中断标志位//中断标志位必须清除//否则中断将连续不断地触发,导致主程序卡死}
}
旋转编码器获取增量值
/*** 函    数:旋转编码器获取增量值* 参    数:无* 返 回 值:自上此调用此函数后,旋转编码器的增量值*/
int16_t Encoder_Get(void)
{/*使用Temp变量作为中继,目的是返回Encoder_Count后将其清零*//*在这里,也可以直接返回Encoder_Count但这样就不是获取增量值的操作方法了也可以实现功能,只是思路不一样*/int16_t Temp;Temp = Encoder_Count;Encoder_Count = 0;return Temp;
}

三、舵机(PWM输出模块)

4. 舵机控制 — [野火]电机应用开发实战指南 文档

1.基本介绍

1)用PWM信号来控制舵机输出轴的角度

2)三根输入线,两根电源线,一根信号线。PWM就是输入到这个信号线来控制舵机。

3)工作原理:输入一个PWM波,输出轴固定在一个角度。

输入PWM信号要求:周期为20ms,高电平宽度为0.5ms~2.5ms

2.硬件电路

1)一般电机都是大功率设备,它的驱动电压也必须是一个大功率的输出设备,如果可以像这样单独提供供电,那就在好不过,也要注意电源的功率是不是达标。如果单独供电,可以直接从STLINK的5V输出脚,引一条接到这里,然后正极接到供电引脚上。供电的负极要和STM32共地,,这样就是使用USB的5V供电,可以带动的。

2)因为舵机中内部自带驱动电路,所以可以直接接上IO就使用。如果内部没有驱动电路,像电机这种大功率的期间,单独使用GPIO是无法驱动的。

3.接线

4.代码编写

输入PWM信号要求:周期为20ms(频率T=1/f=1/20=50HZ),高电平宽度为0.5ms~2.5ms

Freq = CK_PSC / (PSC + 1) / (ARR + 1)===72 000 000/(PSC + 1) / (ARR + 1)

我们可以随意设置ARR和PSC的比例值,使得最后可以符合条件即可。

高电平宽度为0.5ms~2.5ms---》由上面的输出频率对应电机旋转的角度分析可以知道,如果我们想要电机保持0度,则输出的高电平要占整个周期(20ms)的【0.5/20=0.025占的周期宽度】---》则  Duty = CCR / (ARR + 1)  可以知道  当我们将ARR设置为20KHZ(2ms),CRR设置为500(0.5ms)则可以使电机保持0度。如果我们想要电机正转90度张,则应该将CCR的值设置为1500【1500/ 20 000=0.075】

 pwm.c

#include "stm32f10x.h"                  // Device header/*** 函    数:PWM初始化* 参    数:无* 返 回 值:无*/
void PWM_Init(void)
{/*开启时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			//开启TIM2的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);							//将PA1引脚初始化为复用推挽输出	//受外设控制的引脚,均需要配置为复用模式/*配置时钟源*/TIM_InternalClockConfig(TIM2);		//选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟/*时基单元初始化*/TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1;				//计数周期,即ARR的值TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;				//预分频器,即PSC的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            //重复计数器,高级定时器才会用到TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);             //将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元/*输出比较初始化*/ TIM_OCInitTypeDef TIM_OCInitStructure;							//定义结构体变量TIM_OCStructInit(&TIM_OCInitStructure);                         //结构体初始化,若结构体没有完整赋值//则最好执行此函数,给结构体所有成员都赋一个默认值//避免结构体初值不确定的问题TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;               //输出比较模式,选择PWM模式1TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;       //输出极性,选择为高,若选择极性为低,则输出高低电平取反TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;   //输出使能TIM_OCInitStructure.TIM_Pulse = 0;								//初始的CCR值TIM_OC2Init(TIM2, &TIM_OCInitStructure);                        //将结构体变量交给TIM_OC2Init,配置TIM2的输出比较通道2/*TIM使能*/TIM_Cmd(TIM2, ENABLE);			//使能TIM2,定时器开始运行
}/*** 函    数:PWM设置CCR* 参    数:Compare 要写入的CCR的值,范围:0~100* 返 回 值:无* 注意事项:CCR和ARR共同决定占空比,此函数仅设置CCR的值,并不直接是占空比*           占空比Duty = CCR / (ARR + 1)*/
void PWM_SetCompare2(uint16_t Compare)
{TIM_SetCompare2(TIM2, Compare);		//设置CCR2的值
}
//PWM_SetCompare2(500)--->表示500 / 2 0000 = 0.025【这个比例是在20ms为一个周期下的】

servo.c

#include "PWM.h"/*** 函    数:舵机初始化* 参    数:无* 返 回 值:无*/
void Servo_Init(void)
{PWM_Init();									//初始化舵机的底层PWM
}/*** 函    数:舵机设置角度
0   	  500
180 		2500
差值
180			2000---》缩放比例=x/180*2000* 参    数:Angle 要设置的舵机角度,范围:0~180* 返 回 值:无*/
void Servo_SetAngle(float Angle)
{PWM_SetCompare2(Angle / 180 * 2000 + 500);	//设置占空比//将角度线性变换,对应到舵机要求的占空比范围上
}

main.c       

uint8_t KeyNum;			//定义用于接收键码的变量
float Angle;			//定义角度变量int main(void)
{/*模块初始化*/OLED_Init();		//OLED初始化Servo_Init();		//舵机初始化Key_Init();			//按键初始化/*显示静态字符串*/OLED_ShowString(1, 1, "Angle:");	//1行1列显示字符串Angle:while (1){KeyNum = Key_GetNum();			//获取按键键码if (KeyNum == 1)				//按键1按下{Angle += 30;				//角度变量自增30if (Angle > 180)			//角度变量超过180后{Angle = 0;				//角度变量归零}}Servo_SetAngle(Angle);			//设置舵机的角度为角度变量OLED_ShowNum(1, 7, Angle, 3);	//OLED显示角度变量}
}

四、直流电机(PWM输出模块)

直流电机内部没有驱动电路,所以需要外挂一个驱动电路

1.TB6612驱动芯片

STM32——直流电机控制与TB6612FNG驱动芯片 - 古月居

1)这种芯片里面有两路驱动电路,可以独立地控制两个电机。又因为它是H桥型的驱动电路,里面一路有四给开光管,所以就可以控制正反转。

2)像有一些芯片,比如ULN2003,它里面一路只有一个开关管,所以它只能控制电机在一个方向转。

2.正转VS反转

反转工作流程:IN1给低电平,IN2给高电平。电机处于反转状态,那转还是不转取决于PWM。如果PWM给高电平,那输出就是一高一低,有电压差,电机就可以转,这个时候定义的是反转,开始转了。如果PWM给低电平,那输出两个低电平,电机还是不转。IN1给低,IN2给高,PWM高转低不转,如果PWM是一个不断翻转的电平信号,电机就快速反转,停止,反转,停止。如果PWM频率足够快,那电机就可以连续稳定的反转了,并且速度取决于PWM信号的占空比。【占空比越大,速度越快】

3.硬件电路

PWMA,AIN1,AIN2---》对应一个电机

PWMB,BIN1,BIN2---》对应一个电机

4.接线

我们把”VM“接到STLink上相当于接上5V电压(相当于接受USB的供电)

5.代码编写

  pwm.c

#include "stm32f10x.h"                  // Device header/*** 函    数:PWM初始化* 参    数:无* 返 回 值:无*/
void PWM_Init(void)
{/*开启时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			//开启TIM2的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);							//将PA1引脚初始化为复用推挽输出	//受外设控制的引脚,均需要配置为复用模式/*配置时钟源*/TIM_InternalClockConfig(TIM2);		//选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟/*时基单元初始化*/TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1;				//计数周期,即ARR的值TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;				//预分频器,即PSC的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            //重复计数器,高级定时器才会用到TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);             //将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元/*输出比较初始化*/ TIM_OCInitTypeDef TIM_OCInitStructure;							//定义结构体变量TIM_OCStructInit(&TIM_OCInitStructure);                         //结构体初始化,若结构体没有完整赋值//则最好执行此函数,给结构体所有成员都赋一个默认值//避免结构体初值不确定的问题TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;               //输出比较模式,选择PWM模式1TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;       //输出极性,选择为高,若选择极性为低,则输出高低电平取反TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;   //输出使能TIM_OCInitStructure.TIM_Pulse = 0;								//初始的CCR值TIM_OC2Init(TIM2, &TIM_OCInitStructure);                        //将结构体变量交给TIM_OC2Init,配置TIM2的输出比较通道2/*TIM使能*/TIM_Cmd(TIM2, ENABLE);			//使能TIM2,定时器开始运行
}/*** 函    数:PWM设置CCR* 参    数:Compare 要写入的CCR的值,范围:0~100* 返 回 值:无* 注意事项:CCR和ARR共同决定占空比,此函数仅设置CCR的值,并不直接是占空比*           占空比Duty = CCR / (ARR + 1)*/
void PWM_SetCompare2(uint16_t Compare)
{TIM_SetCompare2(TIM2, Compare);		//设置CCR2的值
}
//PWM_SetCompare2(500)--->表示500 / 2 0000 = 0.025【这个比例是在20ms为一个周期下的】

motor.c

/**
* 函    数:直流电机初始化【PWM初始化部分+另外驱动电机转动的引脚】* 参    数:无* 返 回 值:无*/
void Motor_Init(void)
{/*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);		//开启GPIOA的时钟GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);						//将PA4和PA5引脚初始化为推挽输出	PWM_Init();													//初始化直流电机的底层PWM
}/*** 函    数:直流电机设置速度* 参    数:Speed 要设置的速度,范围:-100~100* 返 回 值:无*/
void Motor_SetSpeed(int8_t Speed)
{if (Speed >= 0)							//如果设置正转的速度值{GPIO_SetBits(GPIOA, GPIO_Pin_4);	//PA4置高电平GPIO_ResetBits(GPIOA, GPIO_Pin_5);	//PA5置低电平,设置方向为正转PWM_SetCompare3(Speed);				//PWM设置为速度值}else									//否则,即设置反转的速度值{GPIO_ResetBits(GPIOA, GPIO_Pin_4);	//PA4置低电平GPIO_SetBits(GPIOA, GPIO_Pin_5);	//PA5置高电平,设置方向为反转PWM_SetCompare3(-Speed);			//PWM设置为负的速度值,因为此时速度值为负数,而PWM只能给正数}
}

main.c

由上面实验现象可以得出,当我们设置频率为72 000 000 /(720 -1) =100,000 的时候,电机转动的时候,会发出蜂鸣器的声音。如果我们不想听到,则可以设置频率为人耳听不到的声音【20HZ-20KHZ】之间。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/257983.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis基础系列-持久化

Redis基础系列-持久化 文章目录 Redis基础系列-持久化1. 什么是持久化2. 为什么要持久化3. 持久化的两种方式3.1 持久化方式1:RDB(redis默认持久化方式)3.11 配置步骤-自动触发3.12 配置步骤-手动触发3.12 优点3.13 缺点3.14 检查和修复RDB快照文件3.15 哪些情况会触…

PaddleClas学习3——使用PPLCNet模型对车辆朝向进行识别(c++)

使用PPLCNet模型对车辆朝向进行识别 1 准备环境2 准备模型2.1 模型导出2.2 修改配置文件3 编译3.1 使用CMake生成项目文件3.2 编译3.3 执行3.4 添加后处理程序3.4.1 postprocess.h3.4.2 postprocess.cpp3.4.3 在cls.h中添加函数声明3.4.4 在cls.cpp中添加函数定义3.4.5 在main.…

测试文档---智力冲刺

文章目录 项目背景测试计划UI测试接口测试手工测试 测试总结 项目背景 项目描述:“智力冲刺”是一款网页小游戏,就像我们平时看到的网页游戏一样,前端页面负责展示游戏效果,后端服务器来实现游戏的逻辑。在我们的“智力冲刺”游戏…

容器重启后,Conda文件完整保存(虚拟环境、库包),如何重新安装conda并迁移之前的虚拟环境

Vim安装 容器重启后默认是vi,升级vim,执行命令 apt install -y vim安装 Anaconda 1. 下载Anaconda 其他版本请查看Anaconda官方库 wget https://mirrors.bfsu.edu.cn/anaconda/archive/Anaconda3-2023.03-1-Linux-x86_64.sh --no-check-certificate…

JAVA后端自学技能实操合集

JAVA后端自学技能实操 内容将会持续更新中,有需要添加什么内容可以再评论区留言,大家一起学习FastDFS使用docker安装FastDFS(linux)集成到springboot项目中 内容将会持续更新中,有需要添加什么内容可以再评论区留言,大家一起学习 FastDFS 组名:文件上传后所在的 st…

2023新型智能优化算法-小龙虾优化算法

1 灵感来源 COA的灵感来源于小龙虾的觅食、避暑和竞争行为。觅食阶段和竞争阶段是COA的开发阶段,避暑阶段是COC的探索阶段。 2 数学模型 2.1 初始化种群 采用随机初始化种群,相信大家都能看懂,直接原文献截图。 2.2 确定小龙虾的温度和摄入…

【JavaEE进阶】 Spring使用注解存储对象

文章目录 🌴序言🍀前置⼯作:配置扫描路径🎄添加注解存储 Bean 对象🌳类注解🚩为什么要这么多类注解🚩注解之间的联系 🎋⽅法注解 Bean🚩⽅法注解需要配合类注解使⽤ ⭕总…

远程服务器QEMU+Ubuntu+GRUB+VNC最佳实践

远程服务器QEMUUbuntuGRUBVNC最佳实践 1. 准备2. QEMU启动安装Ubuntu2.1 服务器端2.2 本地端 3. 从服务器终端控制虚拟机GRUB与虚拟机终端 这段时间参与大量内核切换测试工作,实体机需要硬件自检太过笨重,因此主要通过QEMU验证正确性。有一个很大的问题是…

【送书活动四期】被GitHub 要求强制开启 2FA 双重身份验证,我该怎么办?

记得是因为fork了OpenZeppelin/openzeppelin-contracts的项目,之后就被GitHub 要求强制开启 2FA 双重身份验证了,一拖再拖,再过几天帐户操作将受到限制了,只能去搞一下了 目录 2FA是什么为什么要开启 2FA 验证GitHub 欲在整个平台…

销售技巧培训之女装销售技巧

销售技巧培训之女装销售技巧 一、了解目标客户 在销售女装时,了解目标客户是非常重要的。不同年龄段、不同职业、不同收入的女性对女装的需求和偏好都不同。因此,在销售女装时,需要先了解目标客户的特点和需求,以便更好地推荐适…

干货分享|300平米A级机房设计方案

本方案中XXX计算机中心机房建设工程,是XXX的数据中心,机房位于建筑的X层,计算机机房面积300㎡。采购设备以及装修工艺主要用于XXX所属计算机机房装修工程。 考虑到中心机房投资大、使用周期长,而业主业务发展快,现代技…

使用 HTML 地标角色提高可访问性

请务必确保所有用户都可以访问您的网站,包括使用屏幕阅读器等辅助技术的用户。 一种方法是使用 ARIA 地标角色来帮助屏幕阅读器用户轻松浏览您的网站。使用地标角色还有其他好处,例如改进 HTML 的语义并更轻松地设置网站样式。在这篇博文中,我…