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

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

预备知识

编码器

编码器:测转速

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

image.png

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

image.png

image.png

PWM

定时器实现 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. ​​
  4. L298N 模块的连接与使用(stm32 驱动与 51 驱动)
  5. L298N 电机驱动板 - 详细介绍
  6. STM32 定时器---正交编码器模式详解
  7. 带编码器的直流减速电机——基于 STM32F407
  8. PWM 原理 PWM 频率与占空比详解
  9. 单片机_PWM 输出原理详解(含代码)
  10. 玩平衡车系列——编码器使用教程与测速原理
  11. 光电编码器输出脉冲的几种计数方法

相关帖子

欢迎来到这里!

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

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