请问门户网站是什么意思网站搜索功能模块

当前位置: 首页 > news >正文

请问门户网站是什么意思,网站搜索功能模块,郑州快速建站价格,广东平台网站建设找哪家目录 直流有刷电机 工作原理 直流有刷减速电机的重要参数 电路原理与分析 驱动芯片分析 L298N驱动芯片 直流有刷减速电机控制实现 控制速度原理 硬件设计 L298N 野火直流有刷电机驱动板-MOS管搭建板 软件设计1#xff1a;两个直流有刷减速电机按键控制 开发设计 …目录 直流有刷电机 工作原理 直流有刷减速电机的重要参数 电路原理与分析 驱动芯片分析 L298N驱动芯片 直流有刷减速电机控制实现 控制速度原理 硬件设计 L298N 野火直流有刷电机驱动板-MOS管搭建板 软件设计1两个直流有刷减速电机按键控制 开发设计 定时器配置 测试环节 直流有刷减速电机驱动板电流电压采集 ADC配置 测试环节 直流有刷减速电机驱动板限电流、过电压、欠电压保护 ADC配置 测试环节 直流有刷电机 直流有刷电机具有结构简单、易于控制、成本低等特点。 基本的直流有刷电机在电源和电机间只需要两根电缆可以节省配线和连接器所需的空间并降低电缆和连接器的成本。 还可以使用MOSFET/IGBT开关对直流有刷电机进行控制给电机提供足够好的性能并且整个电机控制系统也会比较便宜。 直流有刷电机转速快、扭矩小在某些应用中可能无法满足要求。直流有刷减速电机可以降低转速并提高力矩。 工作原理 直流有刷电机在其电枢转子上绕有大量的线圈所产生强大的磁场与外部磁场相互作用产生旋转运动。 电源通过电刷向线框供电线框就有电流通过在线框两侧放一对磁极NS形成磁场磁力线由N到S。 线框有电流时线框就会收到磁场的作用力按照左手定则红色线框受到力F1蓝色线框受到力F2F1和F2力的方向相反使得线框会转动。 当线框转到90°时换向器改变了线框电流的方向产生的安培力方向不变于是线框会连续旋转。 直流有刷减速电机的重要参数 空载转速正常工作电压下电机不带任何负载的转速单位为r/min即转/分。空载转速由于没有反向力矩所以输出功率和堵转情况不一样该参数只是提供一个电机在规定电压下最大转速的参考。 空载电流正常工作电压下电机不带任何负载的工作电流单位为mA。电机越好该值越小。 负载转速正常工作电压下电机带负载的转速。 负载力矩正常工作电压下电机带负载的力矩单位为N·m即牛·米。 负载电流电机拖动负载时实际检测到的定子电流数值。 堵转力矩在电机受反向外力使其停止转动时的力矩。如果电机堵转现象经常出现则会损坏电机或烧坏电机驱动芯片。所以选电机时除了考虑转速还要考虑堵转。堵转时间一长电机温度上升的很快这个值也会下降的很厉害。 堵转电流在电机受反向外力使其停止转动时的电流。此时电流非常大稍微就可能会烧毁电机在实际使用时应尽量避免。 减速比没有减速齿轮组时转速和有减速齿轮组时转速之比。 功率一般为额定功率单位W即瓦即在额定电压下能够长期正常运转的最大功率也是指电动机在制造厂所规定的额定情况下运行时其输出端的机械功率。 电路原理与分析 当拥有一个直流电机和一节电池只要把电机的两根电源线和电池的电源线连接在一起时电机就可以正常旋转。反接时电机就反向旋转。但实际单片机一般是用H桥电路来驱动电机。 如下图H桥电机驱动电路包括4个三极管和一个电机。要想电机运转就必须导通对角线上的一对三极管所以电流可能会从左到右或从右到左流过电机从而控制电机转向。 当同一侧的Q1和Q2导通时电流将从电源经过Q1和Q2然后直接流到电源负极这个回路中除了三极管外没有经过负载电机这时电流可能会达到最大值而造成烧毁三极管。当同一侧的Q3和Q4导通时也一样。于是可以改进电路原理图。 改进后的电路增加了4个与门和2个非门以及Q1和Q3换成了NPN三极管。这样的组合可以实现一个信号控制两个同一侧的三极管并且可以保证在同一侧的两个三极管不会同时导通即在同一时刻只有一个三极管是导通的。 ENABLE脚接入高电平IN1脚接入高电平AND1_2脚是低电平所以AND1_3脚是低电平所以Q1截止。而AND2_1脚和AND2_2脚都是高电平所以ADN2_3脚是高电平所以Q2导通。然后IN2脚接入低电平AND4_2脚是高电平且AND4_1是高电平所以AND4_3脚是高电平所以Q3导通。而AND3_1脚是高电平AND3_2脚是低电平所以AND3_3脚是低电平所以Q4截止。故电机逆时针转动。 ENABLE脚接入高电平IN1脚接入低电平AND1_2脚是高电平所以AND1_3脚是高电平所以Q1导通。而AND2_1脚是高电平AND2_2脚是低电平所以ADN2_3脚是低电平所以Q2截止。然后IN2脚接入高电平AND4_2脚是低电平AND4_1是高电平所以AND4_3脚是低电平所以Q3截止。而AND3_1脚是高电平AND3_2脚是高电平所以AND3_3脚是高电平所以Q4导通。故电机顺时针转动。 当ENABLE脚接入高电平IN1和IN2都接入同一电平高电平或低电平都只会同时导通上面或下面的两个三极管不会出现同一侧的三极管同时导通的情况。此时电机停止当然ENABLE脚接入低电平时不管IN1、IN2怎样电平都停止电机。 驱动芯片分析 通常在驱动电机时会选择集成H桥的IC因为H桥使用分立元件搭建比较麻烦增加了硬件设计难度。 当我们选择集成IC时需要考虑集成IC是否能满足电机的驱动电压要求是否能承受电机工作时的电流等情况。 如果集成IC无法满足功率要求时还是需要自己使用MOS管、三极管等元件搭建H桥电路这样的分立元件搭建的H桥一般驱动能力也会比集成IC要高。 L298N驱动芯片 L298N是ST公司的产品内部包含4通道逻辑驱动电路是一种二相和四相电机的专门驱动芯片即内含两个H桥的高电压大电流双桥式驱动器接收标准的TTL逻辑电平信号可驱动4.5V~46V、2A以下的电机电流峰值输出可达3A。 原理和刚刚的电路原理分析一致。 直流有刷减速电机控制实现 控制速度原理 PWM通过一定的频率来改变通电和断电的时间从而控制电路输出功率在电机的控制周期中通电时间决定了它的转速。 占空比 通电时间 / 通电时间断电时间即高电平占整个周期的百分比。 假如T1为高电平时间T2为低电平时间T为周期D为占空比则D T1 / T。设电机速度为V最大速度为Vmax则V Vmax * D。当D的大小改变时速度V也会改变所以只要改变占空比就能达到控制电机的速度。 硬件设计 主控有刷电机接口如上图有刷电机接口和无刷电机接口都使用同一个接口。本实验只用到了TIM1_CH1和TIM1_CH2即PA8和PA9来输出PWM信号控制电机需注意主控板需要和电机驱动板共地。 L298N 驱动板可以支持12~46V的宽电压供电并且带输入电压转5V的电压芯片所以驱动板只需一个电源输入具体需要多大电压需要根据电机来选择。 ENABLEA和ENABLEB都是使能输入脚ENABLEA用于控制A桥ENABLEB用于控制B桥可以接到单片机的引脚进行电平控制也可以直接使用跳帽接入5V。 INPUT1和INPUT2是A桥的控制信号INPUT3和INPUT4是B桥的控制信号可以接PWM控制电机。 OUTPUT1和OUTPUT2是A桥的输出信号OUTPUT3和OUTPUT4是B桥的输出信号。 两路电机接口的8个二极管用于防止电机的反电动势损坏L298N。 当E点反电动势为正超过电源0.7V时上端二极管导通因此输出线就被限位在电源电压0.7V上不会超过这个数值。 当E点反电动势为负低于电源-0.7V时下端二极管导通因此输出线就被限位在电源电压-0.7V上不会低于这个数值。 野火直流有刷电机驱动板-MOS管搭建板 野火直流有刷电机驱动板是使用MOS管搭建的大功率H桥电机驱动板。驱动板可支持12V~70V的宽电压输入10A过电流保护电路超过10A可自动禁用电机控制信号最高功率支持700W。实际使用输入电压需要根据电机进行选择同时还具有电流采样电路、编码器接口和电源电压检测电路等。 野火使用MOS管搭建的直流有刷电机驱动板做到了信号完全隔离其它驱动板基本都只是使用光耦隔离了控制信号并没有对ADC采样电路进行隔离。野火不仅使用光耦对控制信号进行了隔离还使用AMC1200SDUBR隔离运放对ADC采样电路进行了隔离。 PWM控制信号使用TLP2362高速光耦进行了隔离SD控制信号使用EL357N光耦进行了隔离。如下图。 下图是使用MOS管搭建的H桥电路使用两个EG2104驱动四个MOS管。 EG2104S主要功能有逻辑信号输入处理、死区时间控制、电平转换功能、悬浮自举电源结构和上下桥图腾柱式输出。逻辑信号输入端高电平阈值为2.5V以上低电平阈值为1.0V以下要求逻辑信号的输出电流小可以使MCU输出逻辑信号直接连接到EG2104S的输入通道上。EG2104S芯片有一个SHUTDOWN引脚逻辑输入控制信号低电平有效强行控制下功率管LO、上功率管HO输出低电平这样可以直接使用这个引脚做软件控制电机的旋转和停止还可以实现硬件的限流和保护。 EG2104S内部集成了死区时间控制电路死区时间波形如下图其中死区时间DT的典型值为640ns。EG2104S采用自举悬浮驱动电源结构大大简化了驱动电源设计只用一路电源电压VCC即可完成高端N沟道MOS管和低端N沟道MOS管两个功率开关器件的驱动给实际应用带来了极大的方便。EG2104S自举电路结构也如下图。RG2104S可以使用外接一个自举二极管和一个自举电容自动完成自举升压功能假如在下管开通、上管关断期间VC自举电容已充到足够的电压VcVCC当HO输出高电平时上管开通、下管关断时VC自举电容上的电压将等效一个电压源作为内部驱动器VB和VS的电源完成高端N沟道MOS管的驱动。 软件设计1两个直流有刷减速电机按键控制 以STM32F4为例。 开发设计 按键1电机1速度加总10个级别。 按键2电机1速度减总10个级别。 按键3电机2速度加总10个级别。 按键4电机2速度减总10个级别。 按键5电机1、电机2同向且都转化方向。 两电机开始状态为停止。 定时器配置 TIM_HandleTypeDef htim1; TIM_HandleTypeDef htim8;void MX_TIM1_Init(void) {TIM_ClockConfigTypeDef sClockSourceConfig {0};TIM_MasterConfigTypeDef sMasterConfig {0};TIM_OC_InitTypeDef sConfigOC {0};TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig {0};htim1.Instance TIM1;htim1.Init.Prescaler 1;htim1.Init.CounterMode TIM_COUNTERMODE_UP;htim1.Init.Period 5599;htim1.Init.ClockDivision TIM_CLOCKDIVISION_DIV1;htim1.Init.RepetitionCounter 0;htim1.Init.AutoReloadPreload TIM_AUTORELOAD_PRELOAD_ENABLE;if (HAL_TIM_Base_Init(htim1) ! HAL_OK){Error_Handler();}sClockSourceConfig.ClockSource TIM_CLOCKSOURCE_INTERNAL;if (HAL_TIM_ConfigClockSource(htim1, sClockSourceConfig) ! HAL_OK){Error_Handler();}if (HAL_TIM_PWM_Init(htim1) ! HAL_OK){Error_Handler();}sMasterConfig.MasterOutputTrigger TIM_TRGO_RESET;sMasterConfig.MasterSlaveMode TIM_MASTERSLAVEMODE_DISABLE;if (HAL_TIMEx_MasterConfigSynchronization(htim1, sMasterConfig) ! HAL_OK){Error_Handler();}sConfigOC.OCMode TIM_OCMODE_PWM1;sConfigOC.Pulse 0;sConfigOC.OCPolarity TIM_OCPOLARITY_HIGH;sConfigOC.OCNPolarity TIM_OCNPOLARITY_HIGH;sConfigOC.OCFastMode TIM_OCFAST_DISABLE;sConfigOC.OCIdleState TIM_OCIDLESTATE_SET;sConfigOC.OCNIdleState TIM_OCNIDLESTATE_RESET;if (HAL_TIM_PWM_ConfigChannel(htim1, sConfigOC, TIM_CHANNEL_1) ! HAL_OK) // 配置PWM通道{Error_Handler();}if (HAL_TIM_PWM_ConfigChannel(htim1, sConfigOC, TIM_CHANNEL_2) ! HAL_OK) // 配置PWM通道{Error_Handler();}sBreakDeadTimeConfig.OffStateRunMode TIM_OSSR_DISABLE;sBreakDeadTimeConfig.OffStateIDLEMode TIM_OSSI_DISABLE;sBreakDeadTimeConfig.LockLevel TIM_LOCKLEVEL_OFF;sBreakDeadTimeConfig.DeadTime 0;sBreakDeadTimeConfig.BreakState TIM_BREAK_DISABLE;sBreakDeadTimeConfig.BreakPolarity TIM_BREAKPOLARITY_HIGH;sBreakDeadTimeConfig.AutomaticOutput TIM_AUTOMATICOUTPUT_DISABLE;if (HAL_TIMEx_ConfigBreakDeadTime(htim1, sBreakDeadTimeConfig) ! HAL_OK){Error_Handler();}HAL_TIM_MspPostInit(htim1);/开始输出PWM/HAL_TIM_PWM_Start(htim1, TIM_CHANNEL_1);HAL_TIM_PWM_Start(htim1, TIM_CHANNEL_2); }void MX_TIM8_Init(void) {TIM_ClockConfigTypeDef sClockSourceConfig {0};TIM_MasterConfigTypeDef sMasterConfig {0};TIM_OC_InitTypeDef sConfigOC {0};TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig {0};htim8.Instance TIM8;htim8.Init.Prescaler 1;htim8.Init.CounterMode TIM_COUNTERMODE_UP;htim8.Init.Period 5599;htim8.Init.ClockDivision TIM_CLOCKDIVISION_DIV1;htim8.Init.RepetitionCounter 0;htim8.Init.AutoReloadPreload TIM_AUTORELOAD_PRELOAD_ENABLE;if (HAL_TIM_Base_Init(htim8) ! HAL_OK){Error_Handler();}sClockSourceConfig.ClockSource TIM_CLOCKSOURCE_INTERNAL;if (HAL_TIM_ConfigClockSource(htim8, sClockSourceConfig) ! HAL_OK){Error_Handler();}if (HAL_TIM_PWM_Init(htim8) ! HAL_OK){Error_Handler();}sMasterConfig.MasterOutputTrigger TIM_TRGO_RESET;sMasterConfig.MasterSlaveMode TIM_MASTERSLAVEMODE_DISABLE;if (HAL_TIMEx_MasterConfigSynchronization(htim8, sMasterConfig) ! HAL_OK){Error_Handler();}sConfigOC.OCMode TIM_OCMODE_PWM1;sConfigOC.Pulse 0;sConfigOC.OCPolarity TIM_OCPOLARITY_HIGH;sConfigOC.OCNPolarity TIM_OCNPOLARITY_HIGH;sConfigOC.OCFastMode TIM_OCFAST_DISABLE;sConfigOC.OCIdleState TIM_OCIDLESTATE_SET;sConfigOC.OCNIdleState TIM_OCNIDLESTATE_RESET;if (HAL_TIM_PWM_ConfigChannel(htim8, sConfigOC, TIM_CHANNEL_1) ! HAL_OK) // 配置PWM通道{Error_Handler();}if (HAL_TIM_PWM_ConfigChannel(htim8, sConfigOC, TIM_CHANNEL_2) ! HAL_OK) // 配置PWM通道{Error_Handler();}sBreakDeadTimeConfig.OffStateRunMode TIM_OSSR_DISABLE;sBreakDeadTimeConfig.OffStateIDLEMode TIM_OSSI_DISABLE;sBreakDeadTimeConfig.LockLevel TIM_LOCKLEVEL_OFF;sBreakDeadTimeConfig.DeadTime 0;sBreakDeadTimeConfig.BreakState TIM_BREAK_DISABLE;sBreakDeadTimeConfig.BreakPolarity TIM_BREAKPOLARITY_HIGH;sBreakDeadTimeConfig.AutomaticOutput TIM_AUTOMATICOUTPUT_DISABLE;if (HAL_TIMEx_ConfigBreakDeadTime(htim8, sBreakDeadTimeConfig) ! HAL_OK){Error_Handler();}HAL_TIM_MspPostInit(htim8);/开始输出PWM/HAL_TIM_PWM_Start(htim8, TIM_CHANNEL_1);HAL_TIM_PWM_Start(htim8, TIM_CHANNEL_2); }void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *tim_baseHandle) {if (tim_baseHandle-Instance TIM1){HAL_RCC_TIM1_CLK_ENABLE();}else if (tim_baseHandle-Instance TIM8){HAL_RCC_TIM8_CLK_ENABLE();} }void HAL_TIM_MspPostInit(TIM_HandleTypeDef timHandle) {GPIO_InitTypeDef GPIO_InitStruct {0};if (timHandle-Instance TIM1){__HAL_RCC_GPIOE_CLK_ENABLE();/**TIM1 GPIO ConfigurationPE9 —— TIM1_CH1PE11 —— TIM1_CH2/GPIO_InitStruct.Pin GPIO_PIN_9 | GPIO_PIN_11;GPIO_InitStruct.Mode GPIO_MODE_AF_PP;GPIO_InitStruct.Pull GPIO_NOPULL;GPIO_InitStruct.Speed GPIO_SPEED_FREQ_LOW;GPIO_InitStruct.Alternate GPIO_AF1_TIM1;HAL_GPIO_Init(GPIOE, GPIO_InitStruct);}else if (timHandle-Instance TIM8){HAL_RCC_GPIOC_CLK_ENABLE();/*TIM8 GPIO ConfigurationPC6 —— TIM8_CH1PC7 —— TIM8_CH2/GPIO_InitStruct.Pin GPIO_PIN_6 | GPIO_PIN_7;GPIO_InitStruct.Mode GPIO_MODE_AF_PP;GPIO_InitStruct.Pull GPIO_NOPULL;GPIO_InitStruct.Speed GPIO_SPEED_FREQ_LOW;GPIO_InitStruct.Alternate GPIO_AF3_TIM8;HAL_GPIO_Init(GPIOC, GPIO_InitStruct);} }void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *tim_baseHandle) {if (tim_baseHandle-Instance TIM1){HAL_RCC_TIM1_CLK_DISABLE();}else if (tim_baseHandle-Instance TIM8){HAL_RCC_TIM8_CLK_DISABLE();} } 测试环节 /*** brief 设置TIM通道的占空比* param channel 通道 1,2* param compare 占空比* note 无* retval 无*/ void TIM_SetPWM_pulse(TIM_HandleTypeDef *TIM_TimeStructure, uint32_t channel, int compare) {switch (channel){case TIM_CHANNEL_1:HAL_TIM_SET_COMPARE(TIM_TimeStructure, TIM_CHANNEL_1, compare);break;case TIM_CHANNEL_2:HAL_TIM_SET_COMPARE(TIM_TimeStructure, TIM_CHANNEL_2, compare);break;} }void motor_init(void) {GPIO_InitTypeDef GPIO_InitStruct;GPIOG_CLK_ENABLE();GPIOE_CLK_ENABLE();// ENA–PG12GPIO_InitStruct.Pin GPIO_PIN_12;GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Speed GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOG, GPIO_InitStruct);// ENB–PE6GPIO_InitStruct.Pin GPIO_PIN_6;HAL_GPIO_Init(GPIOE, GPIO_InitStruct); }/*** brief 设置电机速度* param motor: 电机选择1、2* param speed: 速度占空比* retval 无/ void set_motor_speed(uint8_t motor, uint16_t speed) {if(motor 1){dutyfactor speed;if (direction MOTOR_FWD){TIM_SetPWM_pulse(htim1, TIM_CHANNEL_1, dutyfactor); // 设置比较寄存器的值} else { TIM_SetPWM_pulse(htim1, TIM_CHANNEL_2, dutyfactor); // 设置比较寄存器的值}}else{dutyfactor2 speed;if (direction MOTOR_FWD){TIM_SetPWM_pulse(htim8, TIM_CHANNEL_1, dutyfactor); // 设置比较寄存器的值} else { TIM_SetPWM_pulse(htim8, TIM_CHANNEL_2, dutyfactor); // 设置比较寄存器的值}} }/** brief 设置电机方向* param motor: 电机选择1、2* param motor: 方向选择MOTOR_FWD、MOTOR_REV* retval 无/ void set_motor_direction(uint8_t motor, motor_dir_t dir) {if(motor 1){direction dir;if (direction MOTOR_FWD){TIM_SetPWM_pulse(htim1, TIM_CHANNEL_1, dutyfactor); // 设置比较寄存器的值TIM_SetPWM_pulse(htim1, TIM_CHANNEL_2, 0); // 设置比较寄存器的值}else{TIM_SetPWM_pulse(htim1, TIM_CHANNEL_1, 0); // 设置比较寄存器的值TIM_SetPWM_pulse(htim1, TIM_CHANNEL_2, dutyfactor); // 设置比较寄存器的值}}else{direction2 dir;if (direction2 MOTOR_FWD){TIM_SetPWM_pulse(htim8, TIM_CHANNEL_1, dutyfactor); // 设置比较寄存器的值TIM_SetPWM_pulse(htim8, TIM_CHANNEL_2, 0); // 设置比较寄存器的值}else{TIM_SetPWM_pulse(htim8, TIM_CHANNEL_1, 0); // 设置比较寄存器的值TIM_SetPWM_pulse(htim8, TIM_CHANNEL_2, dutyfactor); // 设置比较寄存器的值}} }/** brief 使能电机* param motor: 电机选择1、2* retval 无/ void set_motor_enable(uint8_t motor) {if(motor 1){HAL_GPIO_WritePin(ENA_GPIO_PORT, ENA_PIN, GPIO_PIN_SET);HAL_TIM_PWM_Start(htim1, TIM_CHANNEL_1); // 使能 PWM 通道 1HAL_TIM_PWM_Start(htim1, TIM_CHANNEL_2); // 使能 PWM 通道 2}else{HAL_GPIO_WritePin(ENB_GPIO_PORT, ENB_PIN, GPIO_PIN_SET);HAL_TIM_PWM_Start(htim8, TIM_CHANNEL_1); // 使能 PWM 通道 1HAL_TIM_PWM_Start(htim8, TIM_CHANNEL_2); // 使能 PWM 通道 2} }/** brief 禁用电机* param motor: 电机选择1、2* retval 无*/ void set_motor_disable(uint8_t motor) {if(motor 1){HAL_GPIO_WritePin(ENA_GPIO_PORT, ENA_PIN, GPIO_PIN_RESET);HAL_TIM_PWM_Stop(htim1, TIM_CHANNEL_1); // 禁用 PWM 通道 1HAL_TIM_PWM_Stop(htim1, TIM_CHANNEL_2); // 禁用 PWM 通道 2}else{HAL_GPIO_WritePin(ENB_GPIO_PORT, ENB_PIN, GPIO_PIN_RESET);HAL_TIM_PWM_Stop(htim8, TIM_CHANNEL_1); // 禁用 PWM 通道 1HAL_TIM_PWM_Stop(htim8, TIM_CHANNEL_2); // 禁用 PWM 通道 2} }void test(void) {IO uint16_t ChannelPulse 0;IO uint16_t ChannelPulse2 0;uint8_t i 0;初始化motor_init();set_motor_enable(1); // 使能电机1set_motor_enable(2); // 使能电机2set_motor_speed(1, ChannelPulse); // 电机1开始状态为停止set_motor_speed(2, ChannelPulse2); // 电机2开始状态为停止while (1){/* 扫描KEY1 /if (Key_Scan(KEY1_GPIO_PORT, KEY1_PIN) KEY_ON){/ 加大占空比即加快电机1的速度 /ChannelPulse 5600 / 10;if (ChannelPulse 5600){ChannelPulse 5600;}set_motor_speed(1, ChannelPulse);}/ 扫描KEY2 /if (Key_Scan(KEY2_GPIO_PORT, KEY2_PIN) KEY_ON){if (ChannelPulse 5600 / 10){ChannelPulse 0;}else{/ 减小占空比即减满电机1的速度 /ChannelPulse - 5600 / 10;}set_motor_speed(1, ChannelPulse);}/ 扫描KEY3 /if (Key_Scan(KEY3_GPIO_PORT, KEY3_PIN) KEY_ON){/ 加大占空比即加快电机2的速度 /ChannelPulse2 5600 / 10;if (ChannelPulse2 5600){ChannelPulse2 5600;}set_motor_speed(2, ChannelPulse2);}/ 扫描KEY4 /if (Key_Scan(KEY4_GPIO_PORT, KEY4_PIN) KEY_ON){if (ChannelPulse2 5600 / 10){ChannelPulse2 0;}else{/ 减小占空比即减满电机1的速度 /ChannelPulse2 - 5600 / 10;}set_motor_speed(2, ChannelPulse2);}/ 扫描KEY5 /if (Key_Scan(KEY5_GPIO_PORT, KEY5_PIN) KEY_ON){/ 转换方向两电机同向 /set_motor_direction(1, (i % 2) ? MOTOR_FWD : MOTOR_REV);set_motor_direction(2, (i % 2) ? MOTOR_FWD : MOTOR_REV);}} } 直流有刷减速电机驱动板电流电压采集 ADC配置 ADC_HandleTypeDef hadc1; DMA_HandleTypeDef hdma_adc1;void MX_ADC1_Init(void) {ADC_ChannelConfTypeDef sConfig {0};/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)/hadc1.Instance ADC1;hadc1.Init.ClockPrescaler ADC_CLOCK_SYNC_PCLK_DIV4;hadc1.Init.Resolution ADC_RESOLUTION_12B;hadc1.Init.ScanConvMode ENABLE;hadc1.Init.ContinuousConvMode ENABLE;hadc1.Init.DiscontinuousConvMode DISABLE;hadc1.Init.ExternalTrigConvEdge ADC_EXTERNALTRIGCONVEDGE_NONE;hadc1.Init.ExternalTrigConv ADC_SOFTWARE_START;hadc1.Init.DataAlign ADC_DATAALIGN_RIGHT;hadc1.Init.NbrOfConversion 2;hadc1.Init.DMAContinuousRequests ENABLE;hadc1.Init.EOCSelection ADC_EOC_SINGLE_CONV;if (HAL_ADC_Init(hadc1) ! HAL_OK){Error_Handler();}/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time./sConfig.Channel ADC_CHANNEL_9;sConfig.Rank 1;sConfig.SamplingTime ADC_SAMPLETIME_3CYCLES;if (HAL_ADC_ConfigChannel(hadc1, sConfig) ! HAL_OK){Error_Handler();}/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time./sConfig.Channel ADC_CHANNEL_8;sConfig.Rank 2;if (HAL_ADC_ConfigChannel(hadc1, sConfig) ! HAL_OK){Error_Handler();} }void HAL_ADC_MspInit(ADC_HandleTypeDef *adcHandle) {GPIO_InitTypeDef GPIO_InitStruct {0};if (adcHandle-Instance ADC1){HAL_RCC_ADC1_CLK_ENABLE();HAL_RCC_GPIOB_CLK_ENABLE();/*ADC1 GPIO ConfigurationPB0 —— ADC1_IN8PB1 —— ADC1_IN9/GPIO_InitStruct.Pin GPIO_PIN_0 | GPIO_PIN_1;GPIO_InitStruct.Mode GPIO_MODE_ANALOG;GPIO_InitStruct.Pull GPIO_NOPULL;HAL_GPIO_Init(GPIOB, GPIO_InitStruct);/* ADC1 DMA Init // ADC1 Init */hdma_adc1.Instance DMA2_Stream0;hdma_adc1.Init.Channel DMA_CHANNEL_0;hdma_adc1.Init.Direction DMA_PERIPH_TO_MEMORY;hdma_adc1.Init.PeriphInc DMA_PINC_DISABLE;hdma_adc1.Init.MemInc DMA_MINC_ENABLE;hdma_adc1.Init.PeriphDataAlignment DMA_PDATAALIGN_HALFWORD;hdma_adc1.Init.MemDataAlignment DMA_MDATAALIGN_HALFWORD;hdma_adc1.Init.Mode DMA_CIRCULAR;hdma_adc1.Init.Priority DMA_PRIORITY_HIGH;hdma_adc1.Init.FIFOMode DMA_FIFOMODE_DISABLE;if (HAL_DMA_Init(hdma_adc1) ! HAL_OK){Error_Handler();}HAL_LINKDMA(adcHandle, DMA_Handle, hdma_adc1);} }void HAL_ADC_MspDeInit(ADC_HandleTypeDef adcHandle) {if (adcHandle-Instance ADC1){__HAL_RCC_ADC1_CLK_DISABLE();/**ADC1 GPIO ConfigurationPB0 —— ADC1_IN8PB1 —— ADC1_IN9/HAL_GPIO_DeInit(GPIOB, GPIO_PIN_0 | GPIO_PIN_1);/* ADC1 DMA DeInit /HAL_DMA_DeInit(adcHandle-DMA_Handle);} }void MX_DMA_Init(void) {/ DMA controller clock enable /__HAL_RCC_DMA2_CLK_ENABLE();/ DMA interrupt init // DMA2_Stream0_IRQn interrupt configuration /HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn); } 测试环节 #define ADC_NUM_MAX 2048 // ADC 转换结果缓冲区最大值 #define VREF 3.3f // 参考电压理论上是3.3可通过实际测量得3.258static uint16_t adc_buff[ADC_NUM_MAX]; // 电压采集缓冲区 static uint16_t vbus_adc_mean 0; // 电源电压 ACD 采样结果平均值 static uint32_t adc_mean_sum 0; // 平均值累加 static uint32_t adc_mean_count 0; // 累加计数/** brief 常规转换在非阻塞模式下完成回调* param hadc: ADC 句柄.* retval 无*/ void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef hadc) {uint32_t adc_mean 0;// 停止 ADC 采样处理完一次数据在继续采样HAL_ADC_Stop_DMA(hadc); / 累加ADC通道9的采样值 /for (uint32_t count 0; count ADC_NUM_MAX; count 2){adc_mean (uint32_t)adc_buff[count];}adc_mean_sum adc_mean / (ADC_NUM_MAX / 2); // 累加电流平均后累加adc_mean_count; // 累加计数adc_mean 0;/ 累加ADC通道8的采样值 */for (uint32_t count 1; count ADC_NUM_MAX; count 2){adc_mean (uint32_t)adc_buff[count];}vbus_adc_mean adc_mean / (ADC_NUM_MAX / 2); // 保存平均值HAL_ADC_Start_DMA(hadc, (uint32_t )adc_buff, ADC_NUM_MAX); // 开始 ADC 采样 } /** brief 获取电流值* param 无* retval 转换得到的电流值*/ int32_t get_curr_val(void) {static uint8_t flag 0;static uint32_t adc_offset 0; // 偏置电压int16_t curr_adc_mean 0; // 电流 ADC 采样结果平均值curr_adc_mean adc_mean_sum / adc_mean_count; // 保存平均值adc_mean_count 0;adc_mean_sum 0;if (flag 17){adc_offset curr_adc_mean; // 多次记录偏置电压待系统稳定偏置电压才为有效值flag 1;}if (curr_adc_mean adc_offset){curr_adc_mean - adc_offset; // 减去偏置电压}else{curr_adc_mean 0;}// 获取电压值float vdc ((float)vbus_adc_mean / 4096.0f * VREF);// 得到电流值电压放大8倍0.02是采样电阻单位mA。电流采样电路得知的return ( (float)vdc / 8.0f / 0.02f * 1000.0f )
}/*** brief 获取电源电压值* param 无* retval 转换得到的电流值*/ float get_vbus_val(void) {// 获取电压值float vdc ((float)vbus_adc_mean / 4096.0f * VREF); // 电压最大值测量电压是电源电压的1/37电流、电压采样电路得知的return ( ((float)vdc - 1.24f) * 37.0f ); }void test(void) {uint8_t flag 0;初始化HAL_ADC_Start_DMA(hadc1, (uint32_t )adc_buff, ADC_NUM_MAX);while(1){if (HAL_GetTick() % 50 0 flag 0) // 每50毫秒读取一次电流、电压{flag 1;int32_t current get_curr_val();printf(电源电压%.2fV电流%dmA\r\n, get_vbus_val(), current);}else if (HAL_GetTick() % 50 ! 0 flag 1){flag 0;}} } 直流有刷减速电机驱动板限电流、过电压、欠电压保护 ADC配置 ADC_HandleTypeDef hadc1; DMA_HandleTypeDef hdma_adc1;/ ADC1 init function / void MX_ADC1_Init(void) {ADC_AnalogWDGConfTypeDef AnalogWDGConfig {0};ADC_ChannelConfTypeDef sConfig {0};/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)/hadc1.Instance ADC1;hadc1.Init.ClockPrescaler ADC_CLOCK_SYNC_PCLK_DIV4;hadc1.Init.Resolution ADC_RESOLUTION_12B;hadc1.Init.ScanConvMode ENABLE;hadc1.Init.ContinuousConvMode ENABLE;hadc1.Init.DiscontinuousConvMode DISABLE;hadc1.Init.ExternalTrigConvEdge ADC_EXTERNALTRIGCONVEDGE_NONE;hadc1.Init.ExternalTrigConv ADC_SOFTWARE_START;hadc1.Init.DataAlign ADC_DATAALIGN_RIGHT;hadc1.Init.NbrOfConversion 2;hadc1.Init.DMAContinuousRequests ENABLE;hadc1.Init.EOCSelection ADC_EOC_SINGLE_CONV;if (HAL_ADC_Init(hadc1) ! HAL_OK){Error_Handler();}/** Configure the analog watchdog*/AnalogWDGConfig.WatchdogMode ADC_ANALOGWATCHDOG_SINGLE_REG;AnalogWDGConfig.HighThreshold (15 / 37 1.24) / 3.3 * 4096;AnalogWDGConfig.LowThreshold (10 / 37 1.24) / 3.3 * 4096;AnalogWDGConfig.Channel ADC_CHANNEL_8;AnalogWDGConfig.ITMode ENABLE;if (HAL_ADC_AnalogWDGConfig(hadc1, AnalogWDGConfig) ! HAL_OK){Error_Handler();}/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time./sConfig.Channel ADC_CHANNEL_9;sConfig.Rank 1;sConfig.SamplingTime ADC_SAMPLETIME_3CYCLES;if (HAL_ADC_ConfigChannel(hadc1, sConfig) ! HAL_OK){Error_Handler();}/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time./sConfig.Channel ADC_CHANNEL_8;sConfig.Rank 2;if (HAL_ADC_ConfigChannel(hadc1, sConfig) ! HAL_OK){Error_Handler();} }void MX_DMA_Init(void) {HAL_RCC_DMA2_CLK_ENABLE();HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn); }void HAL_ADC_MspInit(ADC_HandleTypeDef adcHandle) {GPIO_InitTypeDef GPIO_InitStruct {0};if (adcHandle-Instance ADC1){/ ADC1 clock enable */HAL_RCC_ADC1_CLK_ENABLE();HAL_RCC_GPIOB_CLK_ENABLE();/*ADC1 GPIO ConfigurationPB0 —— ADC1_IN8PB1 —— ADC1_IN9/GPIO_InitStruct.Pin GPIO_PIN_0 | GPIO_PIN_1;GPIO_InitStruct.Mode GPIO_MODE_ANALOG;GPIO_InitStruct.Pull GPIO_NOPULL;HAL_GPIO_Init(GPIOB, GPIO_InitStruct);/* ADC1 DMA Init // ADC1 Init */hdma_adc1.Instance DMA2_Stream0;hdma_adc1.Init.Channel DMA_CHANNEL_0;hdma_adc1.Init.Direction DMA_PERIPH_TO_MEMORY;hdma_adc1.Init.PeriphInc DMA_PINC_DISABLE;hdma_adc1.Init.MemInc DMA_MINC_ENABLE;hdma_adc1.Init.PeriphDataAlignment DMA_PDATAALIGN_HALFWORD;hdma_adc1.Init.MemDataAlignment DMA_MDATAALIGN_HALFWORD;hdma_adc1.Init.Mode DMA_CIRCULAR;hdma_adc1.Init.Priority DMA_PRIORITY_HIGH;hdma_adc1.Init.FIFOMode DMA_FIFOMODE_DISABLE;if (HAL_DMA_Init(hdma_adc1) ! HAL_OK){Error_Handler();}HAL_LINKDMA(adcHandle, DMA_Handle, hdma_adc1);/* ADC1 interrupt Init */HAL_NVIC_SetPriority(ADC_IRQn, 0, 0);HAL_NVIC_EnableIRQ(ADC_IRQn);} }void HAL_ADC_MspDeInit(ADC_HandleTypeDef adcHandle) {if (adcHandle-Instance ADC1){__HAL_RCC_ADC1_CLK_DISABLE();/**ADC1 GPIO ConfigurationPB0 —— ADC1_IN8PB1 —— ADC1_IN9/HAL_GPIO_DeInit(GPIOB, GPIO_PIN_0 | GPIO_PIN_1);/* ADC1 DMA DeInit /HAL_DMA_DeInit(adcHandle-DMA_Handle);/ ADC1 interrupt Deinit /HAL_NVIC_DisableIRQ(ADC_IRQn);} } 测试环节 #define VREF 3.3f // 参考电压理论上是3.3可通过实际测量得3.258 #define ADC_NUM_MAX 2048 // ADC 转换结果缓冲区最大值 #define VBUS_MAX 15 // 电压最大值 #define VBUS_MIN 10 // 电压最小值uint16_t adc_buff[ADC_NUM_MAX]; uint16_t vbus_adc_mean 0; // 电源电压 ACD 采样结果平均值 uint32_t adc_mean_sum 0; // 平均值累加 uint32_t adc_mean_count 0; // 累加计数 uint16_t flag_num 0;/** brief 常规转换在非阻塞模式下完成回调* param hadc: ADC 句柄.* retval 无*/ void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) {uint32_t adc_mean 0;// 停止 ADC 采样处理完一次数据在继续采样HAL_ADC_Stop_DMA(hadc); // 电流数据第一次滤波for (uint32_t count 0; count ADC_NUM_MAX; count 2){adc_mean (uint32_t)adc_buff[count];}adc_mean_sum adc_mean / (ADC_NUM_MAX / 2); // 累加电压adc_mean_count;adc_mean 0;// 电压数据第一次滤波for (uint32_t count 1; count ADC_NUM_MAX; count 2){adc_mean (uint32_t)adc_buff[count];}vbus_adc_mean adc_mean / (ADC_NUM_MAX / 2); // 保存平均值HAL_ADC_Start_DMA(hadc, (uint32_t )adc_buff, ADC_NUM_MAX); // 开始 ADC 采样 }/** brief 在非阻塞模式模拟看门狗回调* param hadc: ADC 句柄.* retval 无*/ void HAL_ADC_LevelOutOfWindowCallback(ADC_HandleTypeDef hadc) {float temp_adc;flag_num; // 电源电压超过阈值电压temp_adc get_vbus_val();if (temp_adc VBUS_MIN temp_adc VBUS_MAX){flag_num 0;}if (flag_num 2048){set_motor_disable(); // 停止电机flag_num 0;printf(电源电压超过限制请检查原因复位开发板在试\r\n);while (1);} }/** brief 获取电流值应定时调用* param 无* retval 转换得到的电流值*/ int32_t get_curr_val(void) {static uint8_t flag 0;static uint32_t adc_offset 0; // 偏置电压int16_t curr_adc_mean 0; // 电流 ACD 采样结果平均值// 电流数据第二次滤波curr_adc_mean adc_mean_sum / adc_mean_count; // 保存平均值adc_mean_count 0;adc_mean_sum 0;if (flag 17){adc_offset curr_adc_mean; // 多次记录偏置电压待系统稳定偏置电压才为有效值flag 1;}if (curr_adc_mean adc_offset){curr_adc_mean - adc_offset; // 减去偏置电压}else{curr_adc_mean 0;}// 获取电压值float vdc ((float)vbus_adc_mean / 4096.0f * VREF);// 得到电流值电压放大8倍0.02是采样电阻单位mA。电流采样电路得知的return ( (float)vdc / 8.0f / 0.02f * 1000.0f )
}/*** brief 获取电源电压值* param 无* retval 转换得到的电流值*/ float get_vbus_val(void) {// 获取电压值float vdc ((float)vbus_adc_mean / 4096.0f * VREF); // 电压最大值测量电压是电源电压的1/37电流、电压采样电路得知的return ( ((float)vdc - 1.24f) * 37.0f ); }#define CURR_MAX 500 // 最大电流单位mAvoid test(void) {uint8_t curr_max_count 0;uint8_t flag 0;uint8_t dir 0;初始化HAL_ADC_Start_DMA(hadc1, (uint32_t *)adc_buff, ADC_NUM_MAX);while(1){if (HAL_GetTick() % 50 0 flag 0) // 每50毫秒读取一次电流、电压{flag 1;int32_t current get_curr_val();printf(电源电压%.2fV电流%dmA\r\n, get_vbus_val(), current);if (current CURR_MAX) // 判断是不是超过限定的值{if (curr_max_count 5) // 连续5次超过{set_motor_disable(); // 电机停止curr_max_count 0;printf(电流超过限制请检查原因复位开发板在试\r\n);while (1);}}}else if (HAL_GetTick() % 50 ! 0 flag 1){flag 0;} } }