预备知识
编码器
编码器:测转速
在下降沿或这上升沿的时候,检测两个端口的值。
脉冲信号的周期定为 2Π,就可以理解啦
PWM
定时器实现 PWM
STC8-PWM/DAC
频率决定其周期。
频率一般取 1KHZ。
模拟电压值:电压*占空比
PWM
最高的精度是 2^15 次方(32768)。
- 根据频率得出周期值。
- 算出占空比对应的周期,以它为最小单位,开始往上加。
DAC
- 配置主频
- 配置精度
- 什么时候高,什么时候低
PWM 控制舵机(伺服电机)
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
第四行:
第六行和第七行:
第八行:允许第 0 通道 PWM 中断
第十一行:允许计数器中断
结果:
输出 2.70KHZ
计算公式:1/(11.0592*1000000*4096(1000H))
例程:19.2.2 两路 PWM 实现互补对称带死区控制的波形
实际上输出互补的两个波形
例程: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 翻转点设置计数值寄存器
注意事项
- 使用 STC8A 的库函数时要注意修改库函数中,PWM 的地址。
- 可以参考官方例程中程序,进行部分修改。
-
//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
脉宽:高电平时间
脉宽测量:(时钟来源内部)上升沿触发,记录当前计数器的值 A1,下降沿时,记录当前计数器的值 A2
(A2-A1)*1/f = 脉宽
脉冲捕获:(时钟来源外部)
高速脉冲输出:(时钟来源主时钟的分频)
在 A1 处拉低,在 A2 处拉高。
一个信号只能测出脉冲个数,两个信号可以测出正转还是反转。
参考资料:
18.3.1 PCA 输出 PWM(6/7/8/10 位)
输出的频率是固定的。
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);
}
频率计算
占空比计算
//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);
学习步骤
- 粗略看一遍手册
- 查看范例程序,对照手册,一个一个去查
L289N
驱动芯片需要和主控芯片共地。
H 桥电路(含续流二极管)
续流二极管:电机是一个感性负载,电流不能突变。MOS 管导通之后,电流不能泄放,电流可以通过肖特基二极管泄放。(电感的瞬时电动势击穿肖特基,从而泄放电流)
参考资料
- H 桥电机驱动电路详解
- H 桥电路原理
- 「珂学原理」No.87「PWM 如何控制电机」
- L298N 模块的连接与使用(stm32 驱动与 51 驱动)
- L298N 电机驱动板 - 详细介绍
- STM32 定时器---正交编码器模式详解
- 带编码器的直流减速电机——基于 STM32F407
- PWM 原理 PWM 频率与占空比详解
- 单片机_PWM 输出原理详解(含代码)
- 玩平衡车系列——编码器使用教程与测速原理
- 旋转编码器如何工作以及如何与 Arduino 一起使用[How To Mechatronics]
- 【Youtube 搬运】直流电动机的工作原理【含中文字幕需手动开启】
- STC8 第九课:PCA 可编程计数器阵列
- 光电编码器输出脉冲的几种计数方法
- STC8 第七课:PWM 脉宽调制函数库及 DAC 数模转换
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于