电机驱动控制 (PCA+L298N+PWM+DAC+ 直流电机 + 编码器 +H 桥)

本贴最后更新于 396 天前,其中的信息可能已经事过景迁

预备知识

编码器

编码器:测转速

在下降沿或这上升沿的时候,检测两个端口的值。

image.png

脉冲信号的周期定为 2Π,就可以理解啦

image.png

image.png

PWM

定时器实现 PWM

第 19 讲-直流电机之 PWM 控制

IMG_693220220411-142030.jpg

IMG_693320220411-142034.jpg

IMG_693520220411-142807.jpg

IMG_693420220411-142239.jpg

IMG_693620220411-142830.jpg

IMG_693920220411-143047.jpg

STC8-PWM/DAC

频率决定其周期。

频率一般取 1KHZ。

模拟电压值:电压*占空比

PWM

最高的精度是 2^15 次方(32768)。

  1. 根据频率得出周期值。
  2. 算出占空比对应的周期,以它为最小单位,开始往上加。

DAC

  1. 配置主频
  2. 配置精度
  3. 什么时候高,什么时候低

PWM 控制舵机(伺服电机)

image.png

0.5ms/20ms*100 =2.5%(0°)

2.5ms/20ms*100= 12.5%(180°)

1.5ms/20ms*100 = 7.5% (中间)

例程:19.2.1 输出任意周期和任意占空比的波形

PWMCR = 0x80; //启动 PWM 模块

void main()
{
 P_SW2 = 0x80;	 
 PWMCKS = 0x00; // PWM 时钟为系统时钟
 PWMC = 0x1000; //设置 PWM 周期为 1000H 个 PWM 时钟
 PWM0T1= 0x0100; //在计数值为 100H 地方输出低电平
 PWM0T2= 0x0500; //在计数值为 500H 地方输出高电平
 PWM0CR= 0x80; //使能 PWM0 输出
 P_SW2 = 0x00;

 PWMCR = 0x80; //启动 PWM 模块

 while (1);
}

第三行:外设端口切换控制寄存器 2 的 EAXFR 置 1

image.png

第四行:image.png

第六行和第七行:image.png

第八行:允许第 0 通道 PWM 中断image.png

第十一行:允许计数器中断image.png

结果:

image.png

输出 2.70KHZ

计算公式:1/(11.0592*1000000*4096(1000H))

例程:19.2.2 两路 PWM 实现互补对称带死区控制的波形

实际上输出互补的两个波形

image.png

例程:19.2.3 PWM 实现渐变灯(呼吸灯)

#define CYCLE           0x1000

void PWM_Isr() interrupt 22
{
    static bit dir = 1;
    static int val = 0;
    char store;

    if (PWMCFG & 0x80)//PWM计数器归零中断标志位 
//当15位的PWM计数器记满溢出归零时,硬件自动将此位置1,并向CPU提出中断请求,此标志
//位需要软件清零。
    {
        PWMCFG &= ~0x80;                        //清中断标志
        if (dir)
        {
            val++;
            if (val >= CYCLE) dir = 0;
        }
        else
        {
            val--;
            if (val <= 1) dir = 1;
        }
  
        store = P_SW2;
        P_SW2 |= 0x80;
        PWM0T2 = val;
        P_SW2 = store;
    }
}

void main()
{
    P_SW2 = 0x80;		//开启读取外部寄存器指令
    PWMCKS = 0x00;                              // PWM时钟为系统时钟
    PWMC = CYCLE;                               //设置PWM周期为
    PWM0T1= 0x0000;             //计时器的值
    PWM0T2= 0x0001;             //
    PWM0CR= 0x80;                               //使能PWM0输出
    P_SW2 = 0x00;		//关闭读取外部寄存器指令

    PWMCR = 0xc0;                               //启动PWM模块
//使能PWM波形发生器,PWM计数器开始计数
//ENPWM控制位既是整个PWM模块的的使能位,也是PWM计数器开始计数的控制位。在PWM
//计数器计数的过程中,ENPWM控制位被关闭时,PWM计数会立即停止,当再次使能ENPWM
//控制位时,PWM的计数会从0开始重新计数,而不会记忆PWM停止计数前的计数值
    EA = 1;

    while (1);
}

PWM 翻转点设置计数值寄存器

image.png

image.png

image.png

注意事项

ZA_IQF8YQVQ37WUTE8.jpg

  1. 使用 STC8A 的库函数时要注意修改库函数中,PWM 的地址。
  2. 可以参考官方例程中程序,进行部分修改。
  3.  //STC8A/STC8F系列-PWM实现渐变灯(呼吸灯)
     #include "reg51.h"
     #include "intrins.h"
    
     //测试工作频率为11.0592MHz
    
     sfr     P_SW2       =   0xba;
     sfr     PWMCFG      =   0xf1;
     sfr     PWMIF       =   0xf6;
     sfr     PWMFDCR     =   0xf7;
     sfr     PWMCR       =   0xfe;
    
     #define PWMC            (*(unsigned int volatile xdata *)0xfff0)
     #define PWMCKS          (*(unsigned char volatile xdata *)0xfff2)
     #define TADCP           (*(unsigned int volatile xdata *)0xfff3)
     #define PWM0T1          (*(unsigned int volatile xdata *)0xff00)
     #define PWM0T2          (*(unsigned int volatile xdata *)0xff02)
     #define PWM0CR          (*(unsigned char volatile xdata *)0xff04)
     #define PWM0HLD         (*(unsigned char volatile xdata *)0xff05)
     #define PWM1T1          (*(unsigned int volatile xdata *)0xff10)
     #define PWM1T2          (*(unsigned int volatile xdata *)0xff12)
     #define PWM1CR          (*(unsigned char volatile xdata *)0xff14)
     #define PWM1HLD         (*(unsigned char volatile xdata *)0xff15)
     #define PWM2T1          (*(unsigned int volatile xdata *)0xff20)
     #define PWM2T2          (*(unsigned int volatile xdata *)0xff22)
     #define PWM2CR          (*(unsigned char volatile xdata *)0xff24)
     #define PWM2HLD         (*(unsigned char volatile xdata *)0xff25)
     #define PWM3T1          (*(unsigned int volatile xdata *)0xff30)
     #define PWM3T2          (*(unsigned int volatile xdata *)0xff32)
     #define PWM3CR          (*(unsigned char volatile xdata *)0xff34)
     #define PWM3HLD         (*(unsigned char volatile xdata *)0xff35)
     #define PWM4T1          (*(unsigned int volatile xdata *)0xff40)
     #define PWM4T2          (*(unsigned int volatile xdata *)0xff42)
     #define PWM4CR          (*(unsigned char volatile xdata *)0xff44)
     #define PWM4HLD         (*(unsigned char volatile xdata *)0xff45)
     #define PWM5T1          (*(unsigned int volatile xdata *)0xff50)
     #define PWM5T2          (*(unsigned int volatile xdata *)0xff52)
     #define PWM5CR          (*(unsigned char volatile xdata *)0xff54)
     #define PWM5HLD         (*(unsigned char volatile xdata *)0xff55)
     #define PWM6T1          (*(unsigned int volatile xdata *)0xff60)
     #define PWM6T2          (*(unsigned int volatile xdata *)0xff62)
     #define PWM6CR          (*(unsigned char volatile xdata *)0xff64)
     #define PWM6HLD         (*(unsigned char volatile xdata *)0xff65)
     #define PWM7T1          (*(unsigned int volatile xdata *)0xff70)
     #define PWM7T2          (*(unsigned int volatile xdata *)0xff72)
     #define PWM7CR          (*(unsigned char volatile xdata *)0xff74)
     #define PWM7HLD         (*(unsigned char volatile xdata *)0xff75)
    
     void main()
     {
         P_SW2 = 0x80;
         PWMCKS = 0x00;                              // PWM时钟为系统时钟
         PWMC = 0x1F40;                              //设置PWM周期为1000H个PWM时钟
    
         PWM0T1= 0x4CD;                             //在计数值为100H地方输出低电平
         PWM0T2= 0x1000;                             //在计数值为500H地方输出高电平
    
         PWM0CR= 0x80;                               //使能PWM0输出
         P_SW2 = 0x00;
    
         PWMCR = 0x80;                               //启动PWM模块
    
         while (1);
     }
    

PCA

image.png

脉宽:高电平时间

脉宽测量:(时钟来源内部)上升沿触发,记录当前计数器的值 A1,下降沿时,记录当前计数器的值 A2

(A2-A1)*1/f = 脉宽

脉冲捕获:(时钟来源外部)

高速脉冲输出:(时钟来源主时钟的分频)

image.png

在 A1 处拉低,在 A2 处拉高。

image.png

image.png

一个信号只能测出脉冲个数,两个信号可以测出正转还是反转。

image.png

参考资料:

18.3.1 PCA 输出 PWM(6/7/8/10 位)

输出的频率是固定的。

image.png

PCA1 的频率:系统时钟/2^6 = 127KHZ

#include "reg51.h"
#include "intrins.h"

//测试工作频率为11.0592MHz

sfr     CCON        =   0xd8;
sbit    CF          =   CCON^7;
sbit    CR          =   CCON^6;
sbit    CCF3        =   CCON^3;
sbit    CCF2        =   CCON^2;
sbit    CCF1        =   CCON^1;
sbit    CCF0        =   CCON^0;
sfr     CMOD        =   0xd9;
sfr     CL          =   0xe9;
sfr     CH          =   0xf9;
sfr     CCAPM0      =   0xda;
sfr     CCAP0L      =   0xea;
sfr     CCAP0H      =   0xfa;
sfr     PCA_PWM0    =   0xf2;
sfr     CCAPM1      =   0xdb;
sfr     CCAP1L      =   0xeb;
sfr     CCAP1H      =   0xfb;
sfr     PCA_PWM1    =   0xf3;
sfr     CCAPM2      =   0xdc;
sfr     CCAP2L      =   0xec;
sfr     CCAP2H      =   0xfc;
sfr     PCA_PWM2    =   0xf4;
sfr     CCAPM3      =   0xdd;
sfr     CCAP3L      =   0xed;
sfr     CCAP3H      =   0xfd;
sfr     PCA_PWM3    =   0xf5;

void main()
{
    CCON = 0x00;				//停止PCA计数
    CMOD = 0x08;                                //PCA时钟为系统时钟
    CL = 0x00;					//PCA计数器的值清0
    CH = 0x00;
    CCAPM0 = 0x42;                              //PCA模块0为PWM工作模式 (允许模块0的脉宽调制输出功能和比较功能)
    PCA_PWM0 = 0x80;                            //PCA模块0输出6位PWM
    CCAP0L = 0x20;                              //PWM占空比为50%[(40H-20H)/40H]
    CCAP0H = 0x20;				//因为使能了比较功能,将计数器的值与CCAP里面的值进行比较
  
    CCAPM1 = 0x42;                              //PCA模块1为PWM工作模式
    PCA_PWM1 = 0x40;                            //PCA模块1输出7位PWM
    CCAP1L = 0x20;                              //PWM占空比为75%[(80H-20H)/80H]
    CCAP1H = 0x20;

    CCAPM2 = 0x42;                              //PCA模块2为PWM工作模式
    PCA_PWM2 = 0x00;                            //PCA模块2输出8位PWM
    CCAP2L = 0x20;                              //PWM占空比为87.5%[(100H-20H)/100H]
    CCAP2H = 0x20;

    CCAPM3 = 0x42;                              //PCA模块3为PWM工作模式
    PCA_PWM3 = 0xc0;                            //PCA模块3输出10位PWM
    CCAP3L = 0x20;                              //PWM占空比为96.875%[(400H-20H)/400H]
    CCAP3H = 0x20;

    CR = 1;                                     //启动PCA计时器

    while (1);
}


参考文章:[文章] 关于 STC 单片机硬件 PWM 的使用分析,这里主要针对需要可调频的介绍

18.3.2 PCA 捕获测量脉冲宽度

unsigned long count0;                           //记录上一次的捕获值
unsigned long count1;                           //记录本次的捕获值
unsigned long length;                           //存储信号的时间长度

void main()
{
    cnt = 0;                                    //用户变量初始化
    count0 = 0;
    count1 = 0;
    length = 0;
    CCON = 0x00;				//停止PCA计数
    CMOD = 0x09;                                //PCA时钟为系统时钟,使能PCA计时中断
    CL = 0x00;					//PCA计数器清0
    CH = 0x00;

    //允许PCA的捕获中断
    CCAPM0 = 0x11;                              //PCA模块0为16位捕获模式(下降沿捕获) 
    CCAPM0 = 0x21;                              //PCA模块0为16位捕获模式(上升沿捕获)
    CCAPM0 = 0x31;                              //PCA模块0为16位捕获模式(边沿捕获)
    //最后开启边沿捕获  

    //捕获寄存器清零(产生边沿信号时,保存发生捕获时的PCA的计数值)
    CCAP0L = 0x00;
    CCAP0H = 0x00;
  
    CR = 1;                                     //启动PCA计时器
    EA = 1;

    while (1);
}

void PCA_Isr() interrupt 7
{
    if (CF)				        //PCA计数器溢出中断标志
    {
        CF = 0;
        cnt++;                                  //PCA计时溢出次数+1
    }
    if (CCF0)	                                //CCF0:PCA模块0中断请求标志
    {
        CCF0 = 0;
        count0 = count1;                        //备份上一次的捕获值
        ((unsigned char *)&count1)[3] = CCAP0L;
        ((unsigned char *)&count1)[2] = CCAP0H;
        ((unsigned char *)&count1)[1] = cnt;
        ((unsigned char *)&count1)[0] = 0;
        length = count1 - count0;              //length保存的即为捕获的脉冲宽度
    }
}

18.3.3 PCA 实现 16 位软件定时

unsigned int value;

#define T50HZ           (11059200L / 12 / 2 / 50)

void PCA_Isr() interrupt 7
{
    CCF0 = 0;		
    CCAP0L = value;
    CCAP0H = value >> 8;
    value += T50HZ;

    P10 = !P10;                                 //测试端口
}

void main()
{
    CCON = 0x00;
    CMOD = 0x00;                                //PCA时钟为系统时钟/12
    CL = 0x00;
    CH = 0x00;
    CCAPM0 = 0x49;                              //PCA模块0为16位定时器模式
    //允许PCA模块0的比较功能 
    //允许PCA模块0的匹配功能
    //允许PCA模块n的匹配中断

    value = T50HZ;
    CCAP0L = value;
    CCAP0H = value >> 8;
    //当PCA模块比较功能使能时,PCA控制器会将当前CL和CH中的计数值与保存在CCAPnL和
CCAPnH中的值进行比较,并给出比较结果;

    value += T50HZ;
    CR = 1;                                     //启动PCA计时器
    EA = 1;

    while (1);
}

18.3.4 PCA 输出高速脉冲

#define T38K4HZ         (11059200L / 2 / 38400)

unsigned int value;

void PCA_Isr() interrupt 7
{
    CCF0 = 0;
    CCAP0L = value;
    CCAP0H = value >> 8;
    value += T38K4HZ;
}

void main()
{
    CCON = 0x00;
    CMOD = 0x08;                                //PCA时钟为系统时钟
    CL = 0x00;	
    CH = 0x00;

    CCAPM0 = 0x4d;                              //PCA模块0为16位定时器模式并使能脉冲输出
    //允许PCA模块n的比较功能
    //允许PCA模块n的匹配功能
    //允许PCA模块n的高速脉冲输出功能
    //允许PCA模块n的匹配中断

    value = T38K4HZ;
    CCAP0L = value;
    CCAP0H = value >> 8;
    value += T38K4HZ;
    CR = 1;                                     //启动PCA计时器
    EA = 1;

    while (1);
}

频率计算

image.png

占空比计算

image.png

   	 //24000000/64 =375KHZ(频率)    2^6=64(占空比精度)
	PCA_InitStructure.PCA_PWM_Wide = PCA_PWM_6bit;		//PCA_PWM_8bit, PCA_PWM_7bit, PCA_PWM_6bit, PCA_PWM_10bit
	PCA_InitStructure.PCA_Value    = 32 << 8;					//对于PWM,高8位为PWM占空比
	PCA_Init(PCA2,&PCA_InitStructure);

	//占空比计算 (64-pwm2)/64
	UpdatePcaPwm(PCA2,pwm2);

学习步骤

  1. 粗略看一遍手册
  2. 查看范例程序,对照手册,一个一个去查

L289N

驱动芯片需要和主控芯片共地。

image.png

image.png

image.png

H 桥电路(含续流二极管)

image.png

image.png

IMG_693020220411-124647.jpg

续流二极管:电机是一个感性负载,电流不能突变。MOS 管导通之后,电流不能泄放,电流可以通过肖特基二极管泄放。(电感的瞬时电动势击穿肖特基,从而泄放电流)

参考资料

  1. H 桥电机驱动电路详解
  2. H 桥电路原理
  3. ​​「珂学原理」No.87「PWM 如何控制电机」
  4. L298N 模块的连接与使用(stm32 驱动与 51 驱动)
  5. L298N 电机驱动板 - 详细介绍
  6. STM32 定时器---正交编码器模式详解
  7. 带编码器的直流减速电机——基于 STM32F407
  8. PWM 原理 PWM 频率与占空比详解
  9. 单片机_PWM 输出原理详解(含代码)
  10. 玩平衡车系列——编码器使用教程与测速原理
  11. 旋转编码器如何工作以及如何与 Arduino 一起使用[How To Mechatronics]
  12. 【Youtube 搬运】直流电动机的工作原理【含中文字幕需手动开启】
  13. STC8 第九课:PCA 可编程计数器阵列
  14. 光电编码器输出脉冲的几种计数方法
  15. STC8 第七课:PWM 脉宽调制函数库及 DAC 数模转换

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...