最简单DIY基于51单片机、PCA9685、IIC、云台的舵机集群控制程序

51单片机物联网智能小车系列文章目录


第一篇:最简单DIY的51蓝牙遥控小车设计方案
第二篇:最简单DIY串口蓝牙硬件实现方案
第三篇:最简单DIY蓝牙PS2遥控器控制蓝牙智能小车
第四篇:最简单DIY基于51单片机的舵机控制器
第五篇:最简单DIY基于蓝牙、51单片机和舵机的钢铁爱国者机关枪控制器
第六篇:最简单DIY基于Android系统的万能蓝牙设备智能遥控器
第七篇:最简单DIY基于51单片机、PCA9685、IIC、云台的舵机集群控制程序


文章目录

  • 51单片机物联网智能小车系列文章目录
  • 前言
  • 一、最简单DIY基于51单片机、PCA9685、IIC、云台的舵机集群控制程序是什么?
  • 二、原理分析
    • 1.现有技术
    • 2.我使用的技术
    • 3.软硬件准备
  • 二、程序设计
    • 1.设计软件逻辑
    • 2.分析代码
  • 三、仿真与调试
  • 总结


前言

    daodanjishui物联网核心原创技术之最简单DIY基于51单片机、PCA9685、IIC、云台的舵机集群控制程序。
    市面上有各种开源智能舵机集群控制器,但是有复杂的有简单的,如果想快速入门51单片机集群控制sg90舵机,这个方案会给你一个快捷高效的方案。


一、最简单DIY基于51单片机、PCA9685、IIC、云台的舵机集群控制程序是什么?

    在第五篇完成了51单片机多个舵机控制的设计的遥杆,读者好奇当时为什么不写控制多个舵机的程序呢?那是因为学习是一个循序渐进的过程,掌握基本的技能才能去举一反三。到现在来看,我第七篇博文是第五篇博文的升级版,可以使用同一个51单片机控制两个舵机云台,并且互相不受影响。舵机控制代码相当精妙,部分是自己的原创代码,如果不好好专研深入思考,是不可能写出这样的代码的,物联网技术就需要万物互联,那能不能用一个模块来控制多个舵机呢?答案是肯定的,这次需要用到PCA9685模块来直接控制舵机,51单片机通过I2C总线控制PCA9685模块。
    第四篇是用定时器0控制一个舵机,第五篇是用定时器0控制两个舵机;它们都是用定时器0产生并控制PWM波最终控制舵机的;现在不再用定时器0直接控制舵机了,用I2C总线来操控PCA模块来控制舵机,全方位开源原创,现在用文字的形式记录下来,这次源码进行了大幅度的升级,代码写得非常精简和奇妙,现在用文字的形式记录下来,对自己童年时代深刻地回忆和对未来技术的展望。“闭门造集群控制”虽然有点痛苦,但是当你看到自己亲手做的舵机集群在上电后自动跑起来的时候,你会发现一切的付出都是值得的!全家福如下图所示:
最简单DIY基于51单片机、PCA9685、IIC、云台的舵机集群控制程序_第1张图片
作品优酷视频演示地址:https://v.youku.com/v_show/id_XNTAwNTYyMDE4MA==.html

直接观看视频

51单片机IIC驱动PCA9685控制四个舵机

二、原理分析

1.现有技术

    这一次我打算采用舵机控制模块来间接控制舵机,很多老外的arduino项目都是用PCA9685来控制舵机的,在电路城很多的卖家都采用这个arduino库来控制舵机,优点有几个:1.直接调用现成的库,如下图所示:
最简单DIY基于51单片机、PCA9685、IIC、云台的舵机集群控制程序_第2张图片
最简单DIY基于51单片机、PCA9685、IIC、云台的舵机集群控制程序_第3张图片
2.直接用arduino集成的IIC的库控制IIC总线直接控制PCA9685,非常方便,配置几个参数就可以搞定多个舵机控制了。 那么我就隆重介绍一下缺点:
(1)51单片机不能使用这些库,stm32也不能用这些库,所以电路城卖的都是免费的arduino舵机程序为主,含金量不是很高。(2)就算可以使用arduino单片机,这个舵机响应速度还是比较慢的,如果我用stm32来控制舵机,会发现流畅很多,几十个舵机一起用都没有压力。(3)网上用51单片机移植Adafruit-PWM-Servo-Driver-Library 的arduino库到51单片机上成功的代码不多,也没有详细注释和说明。

2.我使用的技术

    我用了这个PCA模块一共控制了四个舵机,组合成两个云台。视频中可以看到,这两个云台动作是一样的,先转0度再转60度最后转到80,一直循环下去,因为我在程序中写了一个按照时间顺序来实现彩排效果的舵机动作操,读者可以学到我是怎么按照时间顺序来控制一堆舵机的,绝对够简单暴力,程序简单注释详细老少皆宜。不买云台单单控制舵机也是没有问题的!
    代码说明:这次代码不拖泥带水,直接用51单片机的普通IO口模拟IIC通信协议实现替代arduino的IIC通信库程序,移植arduino的舵机控制库到51单片机上使用,代码含金量不低,除了可以学会如何使用IIC总线之外,还能学会用51控制PCA9685模块从而控制多个舵机。下面是代码的截图:
最简单DIY基于51单片机、PCA9685、IIC、云台的舵机集群控制程序_第4张图片
最简单DIY基于51单片机、PCA9685、IIC、云台的舵机集群控制程序_第5张图片

3.软硬件准备

硬件说明:这次的材料比前两篇博文不一样的地方,多了PCA9685,云台可以不用买,反正我们的重点是控制舵机嘛,某宝上可以十块钱左右买到。舵机的结构和参数如下:
最简单DIY基于51单片机、PCA9685、IIC、云台的舵机集群控制程序_第6张图片

二、程序设计

1.设计软件逻辑

(1)程序采用自动化流水重复执行同一个动作,不需要外加控制指令。那么就需要在死循环一直执行某段程序。

while(1){
								 setPWM(0, 0, SERVO000);//舵机0先转到0度
								 delayms(1000);//延时1S
								 setPWM(0, 0, 239);//就是让舵机0转到60度
								 delayms(1000);//延时1S
								 setPWM(0, 0, SERVO80);//#define SERVO80   284 //80度
								 delayms(1000);//延时1S		                
									
								 setPWM(1, 0, SERVO000);//舵机1先转到0度
								 delayms(1000);//延时1S
								 setPWM(1, 0, 239);//就是让舵机1转到60度
								 delayms(1000);//延时1S
								 setPWM(1, 0, SERVO80);//#define SERVO80   284 //80度
								 delayms(1000);//延时1S	
									
									
									
									//如果需要控制其他的舵机,可以以此类推,呵呵,注意了一个PCA9685最多可以控制16个舵机
								 setPWM(14, 0, SERVO000);//舵机14先转到0度
								 delayms(1000);//延时1S
								 setPWM(14, 0, 239);//就是让舵机14转到60度
								 delayms(1000);//延时1S
								 setPWM(14, 0, SERVO80);//#define SERVO80   284 //80度
								 delayms(1000);//延时1S		
               									
								 setPWM(15, 0, SERVO000);//舵机1先转到0度
								 delayms(1000);//延时1S
								 setPWM(15, 0, 239);//就是让舵机1转到60度
								 delayms(1000);//延时1S
								 setPWM(15, 0, SERVO80);//#define SERVO80   284 //80度
								 delayms(1000);//延时1S	

									
								}

(2)复制现成的51单片机I2C通信代码,网上很多的。

/*---------------------------------------------------------------
                 IIC初始化       
----------------------------------------------------------------*/
void init()
{
    sda=1;                //sda scl使用之前被拉高
    delayus();
    scl=1;
    delayus();
}
/*---------------------------------------------------------------
                 IIC总线开始传输
----------------------------------------------------------------*/
void start()
{
    sda=1;
    delayus();
    scl=1;       //scl高sda拉低 
    delayus();
    sda=0;
    delayus();
                scl=0;
                delayus();
}
/*---------------------------------------------------------------
                 IIC结束
----------------------------------------------------------------*/
void stop()
{
    sda=0;
    delayus();
    scl=1;                         //scl拉高 sda产生上升沿
    delayus();
    sda=1;                   
    delayus();
}
/*---------------------------------------------------------------
                 IIC应答
----------------------------------------------------------------*/
void ACK()
{
    uchar i;
    scl=1;
    delayus();
    while((sda=1)&&(i<255))         
                i++;                                        
    scl=0;                                  
    delayus();
}
/*---------------------------------------------------------------
              写一个字节
----------------------------------------------------------------*/
void write_byte(uchar byte)
{
    uchar i,temp;
    temp=byte;
    for(i=0;i<8;i++)
    {
        temp=temp<<1;  
        scl=0;                  
                                delayus();
                                sda=CY;                 
                                delayus();
                                scl=1;           
                                delayus();
    }
    scl=0;                  
    delayus();
    sda=1;                 
    delayus();
}
/*---------------------------------------------------------------
              读一个字节
----------------------------------------------------------------*/
uchar read_byte()
{
                uchar i,j,k;
                scl=0;
                delayus();
                sda=1;
                delayus();
                for(i=0;i<8;i++)        
                {
                                delayus();
                                scl=1;
                delayus();
                if(sda==1)
                {
                                j=1;
                }
                else j=0;
                k=(k<< 1)|j;  
                scl=0;            
                }
                delayus();
                return k;
}

(3)根据I2C协议组合成PCA9685驱动程序

/*---------------------------------------------------------------
                给PCA9685写字节
----------------------------------------------------------------*/
void PCA9685_write(uchar address,uchar date)
{
                start();
                write_byte(PCA9685_adrr);        //PCA9685
                ACK();                          
                write_byte(address);  //
                ACK();
                write_byte(date); //
                ACK();
                stop();
}
/*---------------------------------------------------------------
         从PCA9685读一个字节
----------------------------------------------------------------*/
uchar PCA9685_read(uchar address)
{
                uchar date;
                start();
                write_byte(PCA9685_adrr); //PCA9685
                ACK();
                write_byte(address);
                ACK();
                start();
                write_byte(PCA9685_adrr|0x01);        //
                ACK();
                date=read_byte();
                stop();
                return date;
}
/*---------------------------------------------------------------
                        PCA9685复位
----------------------------------------------------------------*/
void reset(void) 
{
    PCA9685_write(PCA9685_MODE1,0x0);
}


void begin(void) 
{
    reset();
}

(4)PCA9685参数设置

/*---------------------------------------------------------------
                                        PCA9685参数设置
----------------------------------------------------------------*/
void setPWMFreq(float freq) 
{
                uint prescale,oldmode,newmode;
                float prescaleval;
                freq *= 0.92;  // Correct for overshoot in the frequency setting 
                prescaleval = 25000000;
                prescaleval /= 4096;
                prescaleval /= freq;
                prescaleval -= 1;
                prescale = floor(prescaleval + 0.5);
                
                oldmode = PCA9685_read(PCA9685_MODE1);
                newmode = (oldmode&0x7F) | 0x10; // sleep
                PCA9685_write(PCA9685_MODE1, newmode); // go to sleep
                PCA9685_write(PCA9685_PRESCALE, prescale); // set the prescaler
                PCA9685_write(PCA9685_MODE1, oldmode);
                delayms(2);
                PCA9685_write(PCA9685_MODE1, oldmode | 0xa1); 
}
/*---------------------------------------------------------------
                  PWM波参数设置
num:舵机的序号0~15一共16个舵机
on:PWM上升计数值的范围是0到4096;
off:PWM下降计数的范围是从0到4096;
一个PWM周期分成4096份开始计数,从0开始计算到on个数的时候就是输出高电平
计算到off个数的时候就变成低电平,所以on不等于0的时候就是延时,等于0的时候
off的值与4096的比值就是占空比。
----------------------------------------------------------------*/
void setPWM(uint num, uint on, uint off) 
{
                PCA9685_write(LED0_ON_L+4*num,on);
                PCA9685_write(LED0_ON_H+4*num,on>>8);
                PCA9685_write(LED0_OFF_L+4*num,off);
                PCA9685_write(LED0_OFF_H+4*num,off>>8);
}

缺省代码说明:整个Keil5工程一个文件,非常简洁,很适合二次开发或者学习,目前给出了所有的函数,还剩下一些变量的定义和宏定义,如果耐心够的读者慢慢看也能收获很多,说不定还能再现我这个程序出来,毕竟代码关键的地方都写了注释,这个代码我编写了一周,如果感兴趣的读者想要我全部的源码,麻烦到我指定的地方下载工程吧,尊重原创,尊重劳动成果,我能保证的是我代码是靠谱的,能控制所指定的硬件,视频为证。

2.分析代码

    首先强调一下这个程序使用MDK5写的,如果还有其他需求请联系我,其实用什么软件开发程序都是次要的,关键是你设计产品的逻辑。记得我的老师说过,其实开发语言只是工具而已,关键还是你自己心中是否有完整的运行逻辑机制。
    其实给出的源码我写上了完整的注释了,就说说读者能学到什么内容吧?这份源码可以学习的地方很多的,比如I2C协议,舵机协同控制,PCA9685模块的使用等等,如果要实现控制多个舵机,那么我这个源码绝对物超所值!


三、仿真与调试

这个交给视频演示。比较简单就不详细说明了。

总结

    这次设计方案到此结束,资料我会给出一个PCA9685中文参考手册,真的是很给力的资料,还有一个英文原版的资料,程序源码收费开源,保证绝对可行,整理文档都花了一个早上,说免费下载,其实就是浪费我自己的生命来服务大家,还是要收点费用的,不少读者购买了全套的代码完成快速二次开发,销量证明我的实力。
    下期预告,用电脑端UI界面控制舵机,采用C#编程技术编写UI界面通过串口线控制51单片机,51单片机直接控制舵机。
    现代生活中UI界面原来越多,所以嵌入式UI设计开发永不停止,C#编写的界面也很广泛,那么敬请期待。

代码工程下载链接:https://www.cirmall.com/circuit/22236/
点我直接跳转
PCA9685参考资料

你可能感兴趣的:(51单片机智能小设计,单片机,物联网,编程语言,子模块)