本文将使用STC12C5A60S2配置PWM波,驱动SG90舵机。
采用的开发板包括了CH340芯片,因此下载程序只需要使用MicroUSB转USB连接线使用STC-ISP.exe软件下载程序即可。
1 芯片资源
芯片型号STC12C5A60S2,增强型8051 CPU,1T,单时钟/机器周期,指令代码兼容传统8051,工作电压5.5V-3.5V,工作频率范围0-35MHz,共有4个16位定时器(包括2个16位定时器T0和T1,2路PCA模块实现2个16为定时器),拥有2路PWM(PCA的PWM模式)。
2 舵机控制信号
舵机分为三根线,包括:VCC(5V)、GND和PWM。
PWM波的信号频率在50Hz左右,高电平占空比为2.5%-12.5%,也就是一个周期20ms,高电平占0.5-2.5ms。
2 STC12设置PCA的PWM模式
STC12C5A60S2系列单片机集成了两路可编程计数器阵列(PCA)模块,可用于软件定时器、外部脉冲的捕捉、高速输出以及脉宽调制(PWM)输出。
PCA可以控制2路PWM波。
相关寄存器列表:
寄存器名称 | 功能 |
---|---|
CCON | PCA控制寄存器 |
CMOD | PCA模式寄存器 |
CCAPM0 | PCA模块模式0寄存器 |
CCAPM1 | PCA模块模式1寄存器 |
CL | CPA基位定时器低位(PCA Base Timer Low) |
CH | CPA基位定时器高位(PCA Base Timer High) |
CCAP0L | PCA模块0捕获寄存器低位 |
CCAP0H | PCA模块0捕获寄存器高位 |
CCAP1L | PCA模块1捕获寄存器低位 |
CCAP1H | PCA模块1捕获寄存器高位 |
PCA_PWM0 | PCA PWM模式辅助寄存器0 |
PCA_PWM1 | PCA PWM模式辅助寄存器1 |
AUXR1 | 辅助寄存器1(能够设置输出引脚) |
2.1 CCON:PCA控制寄存器
功能:控制PCA溢出标志位、控制PCA运行状态。PCA模块0和1的中断标志。
寄存器名称 | 地址 | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
---|---|---|---|---|---|---|---|---|---|
CCON | 0xD8 | CF | CR | - | - | - | - | CCF1 | CCF0 |
- CF:PCA计数器阵列溢出标志位。PCA计数器溢出时,CF由硬件置位为1。如果CMOD.0=1(ECF=1),则CF可以用来产生中断。CF可由硬件或者软件置位(为1),但只可通过软件清零。
- CR:PCA计数器阵列运行控制位。软件置位(为1),启动PCA计数。软件清零,关闭PCA计数。
2.2 CMOD:PCA工作模式寄存器
功能:控制空闲模式PCA计数状态、PCA计数脉冲源选项、PCA溢出中断使能。
寄存器名称 | 地址 | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
---|---|---|---|---|---|---|---|---|---|
CMOD | 0xD9 | CIDL | - | - | - | CPS2 | CPS1 | CPS0 | ECF |
CIDL和ECF在此不做介绍,主要介绍CPSn的PCA计数脉冲源选择控制位。
CPS2 | CPS1 | CPS0 | 选择PCA时钟源输入 |
---|---|---|---|
0 | 0 | 0 | 0,SYSCLK/12 |
0 | 0 | 1 | 1,SYSCLK/2 |
0 | 1 | 0 | 2,定时器0的溢出脉冲。通过改变定时器0的分频率,能够实现SYSCLK的1-256分频。 |
0 | 1 | 1 | 3,ECI/P1.2(或P4.1)脚输入的外部时钟(最大速率为SYSCLK/2) |
1 | 0 | 0 | 4,SYSCLK |
1 | 0 | 1 | 5,SYSCLK/4 |
1 | 1 | 0 | 6,SYSCLK/6 |
1 | 1 | 1 | 7,SYSCLK/8 |
但PWM频率不等于PCA频率,PWM波由于要控制占空比,因此每256个PCA周期设置为1个PWM波周期,一部分高电平、一部分低电平。PWM频率=PCA频率/256。
本文主要关注定时器0溢出脉冲输入PCA。
2.3 CCAPM0:PCA比较/捕获寄存器
PCA模块0的比较/捕获寄存器。
寄存器名称 | 地址 | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
---|---|---|---|---|---|---|---|---|---|
CCAPM0 | 0xDA | - | ECOM0 | CAPP0 | CAPN0 | MAT0 | TOG0 | PWM0 | ECCF0 |
- ECOM0允许比较器功能控制位。当ECOM0=1,允许比较器功能。
- CAPP0:正捕获控制位。当CAPP0=1时,允许上升沿捕获。
- CAPN0:负捕获控制位。当CAPN0=1时,允许下降沿捕获。
- MAT0:匹配控制位。当MAT0=1时,PCA计数器与模块的比较/捕获寄存器的值的匹配将置位CCON寄存器的中断标志为CCF0。
- TOG0:翻转控制位、当TOG0=1时,工作在PCA高速输出模式,PCA计数器的值与模块的比较/捕获寄存器的值的匹配将使CCP0脚翻转。
- PWM0:脉宽调节模式。当PWM0=1时,允许,CEX0脚用作脉宽调节输出。
- ECCF0:使能CCF0中断。使能寄存器CCON的比较/捕获标志CCF0,用来产生中断。
模式设置:
由于需要使用PWM模式输出,无需中断,所以CCAPM0=0x42。
2.4 CL、CH:PCA的16位计数器
CL为低8位计数器,CH为高8位计数器。
CL和CH用来保存PCA的装载值,复位值为0x00。
2.5 CCAP0L、CCAP0H:PCA捕获/比较寄存器
CCAP0L为低位字节、CCAP0H为高位字节。当PCA模块用于捕获或比较时,他们用于保存各个模块的16位捕捉计数值。当PCA模块用于PWM模式时,他们用来控制输出的占空比。 复位值均为0x00。
2.6 AUXR1:辅助寄存器引脚功能
辅助寄存器1将单片机的PCA/PWM功能从P1口设置到P4口。
寄存器名称 | 地址 | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
---|---|---|---|---|---|---|---|---|---|
AUXR1 | 0xA2 | - | PCA_P4 | SPI_P4 | S2_P4 | GF2 | ADRJ | - | DPS |
- PCA_ P4:0,缺省PCA在P1口。1,PCA/PWM从P1口切换到P4口;ECI从P1.2切换到P4.1口;PCA0/PWM0从P1.3切换到P4.2口;PCA 1/PWM1从P1.4切换到P4.3口。
- SPI_ P4:0,缺省SPI在P1口。1,SPI从P1口切换到P4口;SPICLK从P1.7切换到P4.3口;MISO从P1.6切换到P4.2口;MOSI从P1.5切换到P4. I口;SS从P1.4切换到P4.0口
- S2_ P4:0,缺省UART2在P1口。1,UART2从P1口切换到P4口;TxD2从P1.3切换到P4.3口;RxD2从P1.2切换到P4.2口。
- GF2:通用标志位
- ADRJ:0,10位A/D转换结果的高8位放在ADC_RES寄存器,低2位放在ADC_RESL寄存器。1,10位A/D转换结果的最高2位放在ADC_RES寄存器的低2位,低8位放在ADC_RESL寄存器。
- DPS:0,使用缺省数据指针DPTR0。1,使用另一个数据指针DPTR1。
3 STC12设置定时器0
3.1 TCON:定时器/计数器控制寄存器
TCON为定时器/计数器T0、T1的控制寄存器,同时也锁存T0、T1溢出中断源和外部请求中断源。本文内只需要T0。
寄存器名称 | 地址 | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
---|---|---|---|---|---|---|---|---|---|
TCON | 0x88 | TF1 | TR1 | TF0 | TR0 | IE1 | IT1 | IE0 | IT0 |
- TF0:定时器/计数器T0溢出中断标志。T0被允许计数以后,从初始开始加1计数,当最高位产生溢出时,由硬件置“1”TF0,向CPU请求中断,一直保持CPU响应该中断时,才由硬件清“0”TF0。
- TR0:定时器T0的运行控制位。该位由软件置位和清零。当GATE(TMOD.3)=0,TR0=1时就运行T0开始计数,TR0=0时禁止T0计数。当GATE(TMOD.3)=1,TR1=0且INT0输入高电平时由硬件清“0”IE1。
- IE0:外部中断0请求源(INT0/P3.2)标志。IE0=1外部中断0向CPU请求中断,当CPU响应外部中断时,由硬件清“0”IE0(边沿触发方式)。
- IT0:外部中断0触发方式控制位。IT0=0时,外部中断0为低电平触发方式,当INT0输入低电平时,置位IE0。采用低电平触发方式时,外部中断源(输入到INT0)必须保持低电平有效,直到该中断被CPU响应,同时在该中断服务程序执行完之前,外部中断源必须被清除(P3.2要变高),否则将产生另一次中断。当IT0=1时,则外部中断0(INT0)端口由“1”->“0”下降沿跳变,激活中断请求标志位IE1,向主机请求中断处理。
3.2 TMOD:定时器/计数器工作模式寄存器
定时和计数功能由特殊功能寄存器TMOD的控制位C/T进行选择。
寄存器名称 | 地址 | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
---|---|---|---|---|---|---|---|---|---|
TMOD | 0x89 | GATE | C/T | M1 | M0 | GATE | C/T | M1 | M0 |
B7-B4为定时器1的控制位,B3-B0为定时器0的控制位。
- GATE:置1时只有在INT0脚为高电平及TR0控制位置1时才可打开定时器/计数器0。
- C/T:定时器/计数器控制位,清零则用作定时器(从内部系统时钟输入),置1用作计数器(从T0/P3.4脚输入)。
- M1、M0:定时器/计数器模式选择。
M1 | M0 | 功能 |
---|---|---|
0 | 0 | 13位定时器/计数器,兼容8048定时模式,TL0只用低5位参与分频,TH0整个8位全用。 |
0 | 1 | 16位定时器/计数器,TL0、TH0全用 |
1 | 0 | 8位自动重装载定时器,当溢出时将TH0存放的值自动重装入TL0 |
1 | 1 | 定时器0此时作为双8位定时器/计数器。TL0作为一个8位定时器/计数器,通过标准定时器0的控制位控制。YH0仅作为一个8位定时器,由定时器1的控制位控制。 |
3.3 TL0、TH0
此寄存器用于控制PWM的占空比。
3.4 AUXR:辅助寄存器
寄存器名称 | 地址 | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
---|---|---|---|---|---|---|---|---|---|
AUXR | 0x8E | T0x12 | T1x12 | UART_M0x6 | BRTR | S2SMOD | BRTx12 | EXTRAM | S1BRS |
3.5 WAKE_CLKO:时钟输出和掉电唤醒寄存器
寄存器名称 | 地址 | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
---|---|---|---|---|---|---|---|---|---|
WAKE_CLKO | 0x8F | PCAWAKEUP | RXD_PIN_IE | T1_PIN_IE | T0_PIN_IE | LVD_WAKE | BRTCLKO | T1CLKO | T0CLKO |
- PCAWAKEUP:在掉电模式下,是否允许PCA上升沿/下降沿中断唤醒powerdown。0,禁止;1,允许。
- RXD_PIN_IE:掉电模式下,允许P3.0(RXD)下降沿置RI,也能使RXD唤醒powerdown。0,禁止;1,允许。
- T0_PIN_IE:掉电模式下,允许T0/P3.4脚下降沿置T0中断标志,也能使T0脚唤醒powerdown。0,禁止;1,允许。
- LVD_WAKE:掉电模式下,是否允许EX_LVD/P4.6低压检测中断唤醒CPU。0,禁止;1,允许。
- BRTCLKO:是否允许将P1.0脚配置为独立波特率发生器(BRT)的时钟输出CLKOUT2。1,允许;0,不允许。
- T0CLKO:是否允许将P3.4/T0脚配置为定时器T0的时钟输出CLKOUT0。1,允许;0,不允许。
4 定时器T0与PWM配置思路
芯片晶振频率为11.0592MHz,输入芯片内得到SYSCLK=11059200Hz。
由于PWM波需要50Hz,PCA将一个周期时长固定划分为256个部分,因此PWM波频率=PCA输入频率/256。
所以PCA输入频率为50*256=12800Hz。
CMOD寄存器中可以设置PCA的输入模式,输入模式分为8种,可以对SYSCLK脉冲、T0溢出脉冲进行分频。
由于SYSCLK/12=11059200/12=921600Hz,远大于PCA输入频率12800Hz,输入模式:0、1、3、4、5、6、7都无法完成分频。因此需要采用输入模式2:定时器0计数溢出脉冲,在1T情况下,分频能够达到SYSCLK/num,num可以为1~256。
芯片有1T模式和12T模式,12T模式是12个周期执行一条指令,兼容8051。
定时器0如果设置为1T模式,采用最大的分频数256,能够输入到PCA的最小频率为SYSCLK/256=11059200/256=43200Hz,也无法满足12800Hz的要求。
因此必须采用12T模式,先将SYSCLK进行12分频,得到频率SYSCLK/12=11059200/12=92600Hz,然后再在定时器0中得到分频。
如图所示,定时器T0采用12T模式(T0x12=0或AUXR.7=0)、定时器(C/T-=0或TMOD.2=0)、模式2:8为自动重载定时器(M1/M0=1/0或TMOD.1/0=1/0)、关闭外部输入(GATE=0或TMOD.3=0)、打开定时器运行控制位(TR0=1或TCON.5=1)。
TL0和TH0都是8位寄存器,两个都通过软件设置相同的值,当TL0捕获到左侧传来的脉冲,从设置好的值到255逐渐递增,然后溢出,这就是定时器的分频过程。计时器T0的溢出脉冲为PCA提供输入信号,同时TH0也会将存储的值传递给TL0,以便进行下一次分频。
上文已经得出输入定时器频率为921600Hz,如果想通过分频得到PCA所需的12800Hz频率,需要分进行921600/12800=72分频。
因此设置定时器0的两个寄存器TL0和TH0为256-72=184。
小结:
1、晶振频率11059200Hz。
2、定时器0采用12T预先分频,得到11059200/12=921600Hz。
3、定时器0设置TL0=TH0=256-72=184,为72分频,得到定时器0溢出频率921600/72=12800Hz。
4、定时器0溢出频率输入到PCA内,PWM波频率为12800/256=50Hz。
5、修改PWM波占空比,设置CCP0L=CCP0H=n(0<n<256),n越大,占空比Duty越大,从0%-100%。
代码如下:
#include "reg51.h"
#include "intrins.h"
/*Declare SFR associated with the PCA */
sfr CCON = 0xD8; //PCA control register
sbit CCF0 = CCON^0; //PCA module-0 interrupt flag
sbit CCF1 = CCON^1; //PCA module-1 interrupt flag
sbit CR = CCON^6; //PCA timer run control bit
sbit CF = CCON^7; //PCA timer overflow flag
sfr CMOD = 0xD9; //PCA mode register
sfr CL = 0xE9; //PCA base timer LOW
sfr CH = 0xF9; //PCA base timer HIGH
sfr CCAPM0 = 0xDA; //PCA module-0 mode register
sfr CCAP0L = 0xEA; //PCA module-0 capture register LOW
sfr CCAP0H = 0xFA; //PCA module-0 capture register HIGH
sfr CCAPM1 = 0xDB; //PCA module-1 mode register
sfr CCAP1L = 0xEB; //PCA module-1 capture register LOW
sfr CCAP1H = 0xFB; //PCA module-1 capture register HIGH
sfr PCAPWM0 = 0xf2;
sfr PCAPWM1 = 0xf3;
sfr AUXR = 0x8E;
sfr WAKE_CLKO = 0x8F;
void Timer0_Init(int i);
void PWM_Init(int i ,int j);
void PWM_Config(float duty);
void delay_ms(int num);
void main()
{
// 初始化定时器0,确定溢出频率
Timer0_Init(50);
// 初始化PWM外设
PWM_Init(0x04,0x42);
while(1)
{
// 设置占空比
PWM_Config(12.5);
delay_ms(256);
// 设置占空比
PWM_Config(10);
delay_ms(256);
// 设置占空比
PWM_Config(7.5);
delay_ms(256);
// 设置占空比
PWM_Config(5);
delay_ms(256);
// 设置占空比
PWM_Config(2.5);
delay_ms(256);
}
}
// i为PWM波频率
void Timer0_Init(int i)
{
int j = 0;
// int k = 0;
// k = i * 256; // 定时器0输出的溢出脉冲,输入到PCA的频率
j = (int)(3600/i); // 定时器0分频数(11059200/12 /i /256 = 3600/i)
EA = 0; // 禁止中断
TMOD |= 0x02; // 配置为八位自动重装载
AUXR |= 0x00; // 12T模式,SYSCLK/12=11059200/12=921600Hz
TL0 = 256-j;
TH0 = 256-j; // 原来是256-j
TR0 = 1; // 启动计数器计数
TF0 = 0; // 清空溢出标志位
WAKE_CLKO = 0x01;
}
void PWM_Init(int i,int j)
{
CL = 0x00;
CH = 0x00;
CMOD = i;
CCAPM0 = j; // 使用比较功能,脉宽调节模式
CR = 1; // 启动PCA计数器
}
void PWM_Config(float duty) // 范围为2.5-12.5
{
int width = 0;
width = (int)(duty*2.56);//-1+0.5;
// duty写的是12.5,实际是12.5%,需要duty/100*256
CCAP0H = 256-width;
CCAP0L = CCAP0H;
}
void delay_ms(int num)
{
int i,j;
for(i=0; i<num;i++){
for(j=0; j<2560;j++);
}
}