源:一个基于ATMEGA128的直流电机抱死程序

先说一下我的硬件情况:一块ATMEGA128实验板;一个带编码器的80:1的变速电机,编码器的输出端连接到单片机的PD4和PD5引脚;一块电机驱动电路,该电路的输入为:24v电源、两路pwm信号输入,输出即为电机的正负极,要用该电路来驱动电机,则必须让两路pwm输入信号的一路占空比为0,另一路不为0,相当于让电机的一极接地,另一极接pwm,通过控制两路pwm的占空比来控制电机的转速和转动方向。pwm信号的输入端连接到单片机的PD6和PD7引脚。

下面是我的程序的设计思路: 这个程序用了两个定时器:timer0和timer1。

timer0用来产生pwm。timer0产生pwm信号是这样实现的:程序中有一个timer0的溢出事件计数器,和两个保存两路pwm信号占空比的变量,当timer0溢出事件计数器计数超过100时,如果某个pwm信号占空比不为0,则把相应pwm引脚置高电平,同时清零此计数器,当此计数器等于某个占空比时,则把相应引脚置低电平,从而实现timer0溢出事件计数器从0计数到100时输出一个周期的pwm信号。通过调节timer0的溢出频率,即可调节pwm信号输出的频率。

timer1用来对编码器的输出进行计数,同时调整pwm的占空比,实现对电机的控制。对编码器的输出计数是利用了timer1的输入捕捉功能,由于电机可以正转,也可以反转,导致编码器的CHA和CHB的输出也不同,所以可以在程序中可以判断电机是正转还是反转,再对编码器的输出脉冲进行计数,当电机正转的时候计数增加,电机反转的时候计数减少,所以编码器的计数值是有正负的。从而可以知道什么时候该通过调整pwm来控制电机。

下面是我的调试过程,也算是一点经验吧:以开始的思路是只要编码器的计数值不为0,我就要让电机反方向转动,以保持电机抱死,发送给电机的pwm是固定的数值,但是这样反而是抱不死,它在前后地抖动,而且pwm的占空比越大,电机抖动得越厉害,这样显然不行;后来想了一个办法,就是如果编码器的计数值在一定的范围内,我就不用让电机反方向转动。因为这个电机是变速电机,如果电机里面只转动一点点,在外面看来就相当于不动,这样的话就给电机预留了一部分转动的空间,用来消除抖动就是说在这个空间内是不发送pwm给电机的,或者说电机两极的pwm占空比都为0。这样一来,当pwm占空比比较低时,是可以消除抖动,但是力气不大,就是说还是可以用钳子拧得动,调了很久都无法在抖动和电机力气之间取得平衡。后来又想了一个办法,在这个基础上再改进,因为之前的pwm占空比都是不变的,所以很难达到令人满意的效果,现在的方法是,根据电机被拧动的角度,或者说编码器的计数值大小来调整pwm的占空比,编码器的计数值偏离0越多(正或负得越大),pwm的占空比就越大,电机的力气也就越大,从而不会出现电机一旦被拧动就马上以最大速度转回去的情况,抖动也就消除了,而且电机力气很大。

编译环境是AVR Studio 5.0,下面是程序代码:

#include <avr/io.h>

#include <avr/interrupt.h> 

int forward = , reverse = ;//存储电机正转和反转pwm占空比的变量

int timer0_count = ;//timer0溢出事件计数器

int capt_count = ;//输入捕捉事件计数器

void port_init(void)

{

PORTA = 0x00;

DDRA  = 0x00;

PORTB = 0x00;

DDRB  = 0x00;

PORTC = 0x00; //m103 output only

DDRC  = 0x00;

PORTD = 0x00;

DDRD  = 0xC0;

PORTE = 0x00;

DDRE  = 0x00;

PORTF = 0x00;

DDRF  = 0x00;

PORTG = 0x00;

DDRG  = 0x00;

}

void timer0_init(void)

{

TCCR0 |= ;//256分频,普通模式

TIMSK |= 0x01;//timer0溢出中断

TCNT0 = 0xFE;//TCNT0赋初值

}

void timer1_init(void)

{

TCCR1B = 0x00;//停止

TCCR1A = 0x00;//普通模式

TCCR1C = 0x00;

TCNT1 = ;//计数初值

TCCR1B = 0xC4;//启动定时器,256分频,使能输入捕捉噪声抑制器,输入捕捉触发沿选择:上升沿

TIMSK = 0x24;//输入捕捉中断使能,T/C1溢出中断使能

}

/************************************************************************/

/*  timer0溢出中断函数,产生提供给电机的pwm                             */

/************************************************************************/

ISR(TIMER0_OVF_vect<span style="color: rgb(255, 0, 0);">)//200kHz

</span>{

TCNT0 = 0xFE;//TCNT0重新赋值

//当timer0_count等于100时,如果正转或反转的占空比不为0,则相应引脚输出高电平

if(++timer0_count >= )//<span style="color: rgb(255, 0, 0);">对timer0溢出事件计数100次,相当于100分频,最后输出到电机的pwm频率是2kHz

</span>{

timer0_count = ;

if(forward != <span style="color: rgb(255, 0, 0);">)//forward, reverse存储电机正转和反转pwm占空比的变量

</span>{PORTD |= (<<);}

if(reverse != )

{PORTD |=(<<);}

}

//<span style="color: rgb(255, 0, 0);">当timer0_count等于正转或反转的占空比时,相应引脚输出低电平,实现输出pwm信号

</span>if(timer0_count == forward)

{PORTD &= ~( << );}

if(timer0_count == reverse)

{PORTD &= ~( << );}

}

/************************************************************************/

/*  timer1输入捕捉中断函数,对编码器输出的上升沿进行计数              */

/************************************************************************/

ISR(TIMER1_CAPT_vect)

{

  if(PIND & ( << ))//电机反转

  {capt_count--;}//输入捕捉计数器减1

  else               //电机正转

  {capt_count++;}//输入捕捉计数器加1

}

/************************************************************************/

/*  <span style="color: rgb(255, 0, 0);">timer1溢出中断函数,100Hz,用于调整电机转速和转动的方向,实现电机抱死</span>*/

/************************************************************************/

ISR(TIMER1_OVF_vect)

{

TCNT1 = ;                           //重新给TCNT1赋值

static unsigned char <span style="color: rgb(255, 0, 0);">motor_state = ;    //电机的状态,标志电机是正转还是反转,0:正转,1:反转

</span>switch(motor_state)

{

case <span style="color: rgb(255, 0, 0);">://电机正转时

</span>if(capt_count > )              <span style="color: rgb(255, 0, 0);">//如果编码器正转计数超过40,则电机需要反转,以保持电机不动

</span>{reverse = capt_count - ;} //直接把编码器计数值减去40,作为反转的占空比

else if(capt_count < )          <span style="color: rgb(255, 0, 0);">//如果编码器计数值小于0

</span>{motor_state = ;}           //进入状态1

else                            <span style="color: rgb(255, 0, 0);"> //如果编码器计数值在0~40内,为了不发生抖动,不需要反转

</span>{reverse = ;}               //反转的占空比为0,相当于负极接地

forward = ;                     //正转的占空比为0,相当于正极接地

break;

case :

if(capt_count < -)             <span style="color: rgb(255, 0, 0);">//如果编码器反转计数超过40,则电机需要正转</span>,以保持电机不动

{forward = (-capt_count) - ;}//直接把编码器计数值减去40,作为正转的占空比

else if(capt_count > )          <span style="color: rgb(255, 0, 0);">//如果编码器计数值大于0

</span>{motor_state = ;}           //返回状态0

else                             <span style="color: rgb(255, 0, 0);">//如果编码器计数值在-40~0内,为了不发生抖动,不需要正转

</span>{forward = ;}               //正转的占空比为0,相当于正极接地

reverse = ;                     //反转的占空比为0 ,相当于负极接地

break;

default:

break;

}

}

void Init_Devices(void)

{

cli();//关闭全局中断

port_init();//I/O口初始化

timer1_init();//定时/计数器1初始化

timer0_init();//计时/计数器0初始化

sei();//打开全局中断

}

int main(void)

{

    Init_Devices();

    while()

    {}

    return ;

}

一个基于ATMEGA128的直流电机抱死程序(转)的更多相关文章

  1. c++下基于windows socket的服务器客户端程序(基于UDP协议)

    前天写了一个基于tcp协议的服务器客户端程序,今天写了一个基于UDP协议的,由于在上一篇使用TCP协议的服务器中注释已经较为详细,且许多api的调用是相同的,故不再另外注释. 使用UDP协议需要注意几 ...

  2. 在C#/.NET应用程序开发中创建一个基于Topshelf的应用程序守护进程(服务)

    本文首发于:码友网--一个专注.NET/.NET Core开发的编程爱好者社区. 文章目录 C#/.NET基于Topshelf创建Windows服务的系列文章目录: C#/.NET基于Topshelf ...

  3. 如何基于OM模型使用C#在程序中给SharePoint的BCS外部数据类型的字段赋值

    概述: 外部内容类型和数据,SharePoint从2010这个版本开始就对BCS提供非常强大的支持,点点鼠标就可以取代以前直接编辑XML的方式来设置SharePoint到SQL数据库的连接.非常方便地 ...

  4. 公布一个基于 Reactor 模式的 C++ 网络库

    公布一个基于 Reactor 模式的 C++ 网络库 陈硕 (giantchen_AT_gmail) Blog.csdn.net/Solstice 2010 Aug 30 本文主要介绍 muduo 网 ...

  5. 如何创建一个基于 MSBuild Task 的跨平台的 NuGet 工具包

    MSBuild 的 Task 为我们扩展项目的编译过程提供了强大的扩展性,它使得我们可以用 C# 语言编写扩展:利用这种扩展性,我们可以为我们的项目定制一部分的编译细节.NuGet 为我们提供了一种自 ...

  6. 如何创建一个基于命令行工具的跨平台的 NuGet 工具包

    命令行可是跨进程通信的一种非常方便的手段呢,只需启动一个进程传入一些参数即可完成一些很复杂的任务.NuGet 为我们提供了一种自动导入 .props 和 .targets 的方法,同时还是一个 .NE ...

  7. 基于Shiro,JWT实现微信小程序登录完整例子

    小程序官方流程图如下,官方地址 : https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html ...

  8. 基于 SailingEase WinForm Framework 开发客户端程序(3:实现菜单/工具栏按钮的解耦及状态控制)

    本系列文章将详细阐述客户端应用程序的设计理念,实现方法. 本系列文章以  SailingEase WinForm Framework 为基础进行设计并实现,但其中的设计理念及方法,亦适用于任何类型的客 ...

  9. WeText项目:一个基于.NET实现的DDD、CQRS与微服务架构的演示案例

    最近出于工作需要,了解了一下微服务架构(Microservice Architecture,MSA).我经过两周业余时间的努力,凭着自己对微服务架构的理解,从无到有,基于.NET打造了一个演示微服务架 ...

随机推荐

  1. FZU 2086 餐厅点餐(枚举)

    ///个人感觉vector好看一点 #include<iostream> #include<cstdio> #include<cstring> #include&l ...

  2. 6--OC--封装 继承 多态

    OC中的类的三大特性类: 继承,封装,多态 一. 封装 封装就是对类中的一些字段,方法进行保护,不被外界所访问到,有一种权限的控制功能,这样我们在定义类的时候,哪些字段和方法不想暴露出去,哪些字段和方 ...

  3. 学习笔记——策略模式Strategy

    策略模式,与模板模式一样,都是为了将接口和算法实现解耦,但策略模式更主要是整体算法的替换,而模板模式主要是流程一致,部分算法的替换. 个人理解为,一般算法替换,使用策略模式,当算法流程一致,可以提取为 ...

  4. fzu Problem - 2232 炉石传说(二分匹配)

    题目链接:http://acm.fzu.edu.cn/problem.php?pid=2232 Description GG学长虽然并不打炉石传说,但是由于题面需要他便学会了打炉石传说.但是传统的炉石 ...

  5. 设计模式---Manager(管理器)

    设计模式之美:Manager(管理器) 索引 意图 结构 参与者 适用性 效果 实现 实现方式(一):Manager 模式的示例实现. 意图 将对一个类的所有对象的管理封装到一个单独的管理器类中. 这 ...

  6. JSP文件上传--Smartupload组件

    把smartupload.jar copy到D:\apache-tomcat-7.0.57\lib下. 创建htm上传文件:smartupload_demo01.htm 由于是上传文件,需要对表单进行 ...

  7. Android系统权限及签名

    Android系统权限及签名   2015-03-23 19:13:33CSDN-chen52671-点击数:50     Android权限及签名 引子 现象:系统中的一个定制Service,服务是 ...

  8. Python3基础 函数 默认值参数示例

    镇场诗: 诚听如来语,顿舍世间名与利.愿做地藏徒,广演是经阎浮提. 愿尽吾所学,成就一良心博客.愿诸后来人,重现智慧清净体.-------------------------------------- ...

  9. StrictMode使用详解

    http://hb.qq.com/a/20110914/000054.htm http://www.android100.org/html/201204/25/1097.html http://www ...

  10. SSL 通信原理及Tomcat SSL 双向配置

    SSL 通信原理及Tomcat SSL 双向配置 目录1 参考资料 .................................................................. ...