
图1-1H桥电路图
H桥中由两路推挽电路组成的,上接正极,下接负极,A、C端就是一路推挽电路,当A端MOS管导通,C端MOS管断开,那么左边输出就接在VM的正极,A端断开,C端导通就是接在PGND的电源负极;如果有两路推挽电路,A、D端导通,B、C端断开,电流就是从左往右流动;B、C端导通,A、D端断开,电流就是从右往左流动。H桥可以控制电流流动的反向,所以就可以控制电机的转向。

图2-1TB6612驱动模块
VM:电机电源正极,是驱动电压输入端,范围是4.5V~10V
VCC:逻辑电平输入端,范围2.7V~5.5V,需要与控制器的电源保持一致。(这边我们是使用STM32,与STM32共用一个电源即可)
GND:接系统负极即可
AO1/2、BO1/2:两路电机的输出
PWMAB、AIN1/2、BIN1/2:这三个引脚则是控制A、B两路中的一路电机,连接到STM32的GPIO口即可,PWM引脚需要接到PWM信号输出端,其他两个引脚接任意两个普通GPIO口即可
STBY:待机控制引脚,接GND,芯片则不工作,处于待机状态;接逻辑电源VCC,芯片正常工作。这个引脚如果不需要待机模式,直接VCC即可;需要的话接GPIO口给高低电平,既可以控制。
| A/BIN1 | A/BIN2 | 模式状态 |
| H | H | 制动 |
| H | L | 正转 |
| L | H | 反转 |
| L | L | 制动 |
当加入了PWM后,便可以通过占空比调节速度。

图3-1A4950引脚

图3-2芯片引脚图说明
| AIN1 | AIN2 | 直流电机状态 (AO1和AO2) |
| 任意 | 任意 | 停止 |
| 0 | 0 | 停止 |
| 0 | 1 | 正转 |
| 1 | 0 | 反转 |
| 1 | 1 | 刹车 |
A4950驱动板的四种驱动方式:
标号 1:芯片 IN1 端口输入一定的占空比 PWM,IN2 为低电平,此时芯片的输出端口会出去一个正电流。为电机正转。
标号 2:芯片IN1 端口输入低电平,IN2 端口输入一定的占空比 PWM,此时芯片的输出端口会出去一个负电流。为电机反转。
标号 3:芯片IN1 端口输入高电平,IN2 端口输入一定的占空比 PWM,此时芯片的输出端口会出去一个正电流。为电机正转。
标号 4:芯片IN1 端口输入一定的占空比 PWM,IN2 为高电平,此时芯片的输出端口会出去一个负电流。为电机反转。
我们可以选择标号 1和标号 4,只需要在一个 IN1 输入 pwm.另一个IN2 输入高电平或者低电平就可以实现控制电机的速度和正反转。
具体信息可以参考这个博主写的驱动芯片原理,写的很详细 电机驱动芯片——DRV8833、TB6612、A4950、L298N的详解与比较_朽木白露的博客-CSDN博客_电机驱动芯片原理
需要的硬件有:F103C8T6,OLED屏,A4950驱动板,电机,若干杜邦线(公对母),(在这里我使用的是Jlink,所以我需要多加一个电源给驱动板)
#include "stm32f10x.h" // Device header
#include "PWM.h"
void Motor_Init(void)
{
PWM_Init();//PWM初始化
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//打开APB2时钟
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
void Motor_SetSpeed(int8_t Speed)
{
if(Speed >= 0)
{
//设置电机的正反转,由高电平和低电平来决定极性
GPIO_SetBits(GPIOA,GPIO_Pin_2);//获得高电平
PWM_Setcompare1(Speed);
}
else
{
GPIO_ResetBits(GPIOA,GPIO_Pin_2);//获得低电平
PWM_Setcompare1(-Speed);
//这时候setcompare为负数,Setcompare必须传正数,所以speed前面必须加一个负号
}
}
在Motor.c中GPIO的模式需要选用 GPIO_Mode_Out_PP(推挽输出模式)。
注意:setcompare为负数时,Setcompare必须传正数,所以speed前面必须加一个负号
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//注意是开启APB1的时钟函数,因为TIM2是APB1总线的外设
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//选择时基单元的时钟
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
TIM_InternalClockConfig(TIM2);
//定时器上电后默认是使用内部时钟,如果不调用,也是使用内部时钟,可以不写
//TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x00);
//通过ETR引脚的外部时钟模式2配置
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision =TIM_CKD_DIV1;//指定时钟分频
TIM_TimeBaseInitStructure.TIM_CounterMode =TIM_CounterMode_Up;//计数器模式
TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; //周期,ARR自动重装器的值
TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;//PSC 预分频器的值
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重复计数器的值,是高级计数器才有的
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
//配置时基单元
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);//给结构体赋初始值,不用一一列出
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2 ;//设置输出比较的模式
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//设置输出使能
TIM_OCInitStructure.TIM_Pulse = 0;//设置CCR
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
//周期ARR;预分频PSC;CCR这三个值,共同决定输出PWM的周期和占空比
TIM_Cmd(TIM2,ENABLE);//启动定时器
}
void PWM_Setcompare1(uint16_t Compare)
{
TIM_SetCompare1(TIM2, Compare);
}
这里的PWM.c程序是根据上一篇博客修改的,不清楚怎么修改的可以参考上一篇文章喔
PWM的驱动使用(呼吸灯)_tz得像个小孩的博客-CSDN博客
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "Timer.h"
#include "OLED.h"
#include "Key.h"
#include "Motor.h"
uint8_t KeyNum;//
int8_t Speed;
int main(void)
{
OLED_Init();
Motor_Init();
Key_Init();
Motor_SetSpeed(-80);
OLED_ShowString(1, 1, "Speed:");
while(1)
{
KeyNum = Key_GetNum();
if (KeyNum == 1)
{
Speed += 20;
if (Speed > 100)
{
Speed = -100;
}
}
Motor_SetSpeed(Speed);
OLED_ShowSignedNum(1, 7, Speed, 3);
}
}

程序中由于A4950驱动板的逻辑电路与TB6612不同,当Speed显示正数时,电机的转速随着数值的增大而增大;但是在Speed显示为负数时,电机的转速会随着数值(PWM的值)的减小,电机的速度会越来越快。
PWM.c的程序大差不差,但是在接IO比A4950多了一个引脚,所以具体程序的区别在于Motor.c程序中,程序的呈现效果是Speed的数值为正为正转,负值则为反转,数值越大转速越快。这里TB6612的呈现效果与A4950不一样。
#include "stm32f10x.h" // Device header
#include "PWM.h"
void Motor_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//打开APB2时钟
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);
GPIO_SetBits(GPIOA,GPIO_Pin_4|GPIO_Pin_5);
PWM_Init();//PWM初始化
}
void Motor_SetSpeed(int8_t Speed)
{
if(Speed >= 0)
{
//设置电机的正反转,由高电平和低电平来决定极性
GPIO_SetBits(GPIOA,GPIO_Pin_4);//获得高电平
GPIO_ResetBits(GPIOA,GPIO_Pin_5);//获得低电平
PWM_Setcompare3(Speed);
}
else
{
GPIO_SetBits(GPIOA,GPIO_Pin_5);//获得高电平
GPIO_ResetBits(GPIOA,GPIO_Pin_4);//获得低电平
PWM_Setcompare3(-Speed);
//这时候setcompare为负数,Setcompare必须传正数,所以speed前面必须加一个负号
}
}
总结:每个驱动板的驱动逻辑不相同,个人认为A4950驱动的程序没有调试好,有待改进。
如果本篇文章部分为个人理解,如果发现错误可以告诉我一下,进行改进,虚心学习。
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。问题1)我想知道rubyonrails是否有功能类似于primefaces的gem。我问的原因是如果您使用primefaces(http://www.primefaces.org/showcase-labs/ui/home.jsf),开发人员无需担心javascript或jquery的东西。据我所知,JSF是一个规范,基于规范的各种可用实现,prim
本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01 客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02 数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit
文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,
LL库和HAL库简介LL:Low-Layer,底层库HAL:HardwareAbstractionLayer,硬件抽象层库LL库和hal库对比,很精简,这实际上是一个精简的库。LL库的配置选择如下:在STM32CUBEMX中,点击菜单的“ProjectManager”–>“AdvancedSettings”,在下面的界面中选择“AdvancedSettings”,然后在每个模块后面选择使用的库总结:1、如果使用的MCU是小容量的,那么STM32CubeLL将是最佳选择;2、如果结合可移植性和优化,使用STM32CubeHAL并使用特定的优化实现替换一些调用,可保持最大的可移植性。另外HAL和L
我使用的是最新版本的Chrome(32.0.1700.107)和Chrome驱动程序(V2.8)。但是当我在Ruby中使用以下代码运行示例测试时:require'selenium-webdriver'WAIT=Selenium::WebDriver::Wait.new(timeout:100)$driver=Selenium::WebDriver.for:chrome$driver.manage.window.maximize$driver.navigate.to'https://www.google.co.in'defapps_hoverele_hover=$driver.find_
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。多年来,我一直在使用多种语言进行编程,并且认为自己总体上相当擅长。但是,我从未编写过任何自动化测试:没有单元测试,没有TDD,没有BDD,什么都没有。我已经尝试开始为我的项目编写适当的测试套件。我可以看到在进行任何更改后能够自动测试项目中所有代码的理论值(value)。我可以看到像RSpec和Mocha这样的测试框架应该如何使设置和运行所述测试变得相当容易
如果我在功能规范中调用url_for,它会返回一个以http://www.example.com/开头的绝对URL.Capybara会很乐意尝试加载该站点上的页面,但这与我的应用程序无关。以下是重现该问题的最少步骤:从这个Gemfile开始:source'https://rubygems.org'gem"sqlite3"gem"jquery-rails"gem"draper"gem"rails",'4.1.0'gem"therubyracer"gem"uglifier"gem"rspec-rails"gem"capybara"gem"poltergeist"gem"launchy"运行
在笔者前面有一篇文章《驱动开发:断链隐藏驱动程序自身》通过摘除驱动的链表实现了断链隐藏自身的目的,但此方法恢复时会触发PG会蓝屏,偶然间在网上找到了一个作者介绍的一种方法,觉得有必要详细分析一下他是如何实现的进程隐藏的,总体来说作者的思路是最终寻找到MiProcessLoaderEntry的入口地址,该函数的作用是将驱动信息加入链表和移除链表,运用这个函数即可动态处理驱动的添加和移除问题。MiProcessLoaderEntry(pDriverObject->DriverSection,1)添加MiProcessLoaderEntry(pDriverObject->DriverSection,
目录一、ESP32简单介绍二、ESP32Wi-Fi模块介绍三、ESP32Wi-Fi编程模型四、ESP32Wi-Fi事件处理流程 五、ESP32Wi-Fi开发环境六、ESP32Wi-Fi具体代码七、ESP32Wi-Fi代码解读6.1主程序app_main7.2自定义代码wifi_init_sta()八、ESP32Wi-Fi连接验证8.1测试方法8.2服务器模拟工具sscom58.3测试代码8.4测试结果前言为了开发一款亚马逊物联网产品,开始入手ESP32模块。为了能够记录自己的学习过程,特记录如下操作过程。一、ESP32简单介绍ESP32是一套Wi-Fi(2.4GHz)和蓝牙(4.2)双模解决方
有道无术,术尚可求,有术无道,止于术。本系列SpringBoot版本3.0.4本系列SpringSecurity版本6.0.2本系列SpringAuthorizationServer版本1.0.2源码地址:https://gitee.com/pearl-organization/study-spring-security-demo文章目录前言1.OAuth2AuthorizationServerMetadataEndpointFilter2.OAuth2AuthorizationEndpointFilter3.OidcProviderConfigurationEndpointFilter4.N