12系列的PWM输出
STC12C5A60S2内部集成了两路可编程计数器阵列(PCA)可以用做脉宽调制(PWM)输出。脉宽调制是将模拟信号转换为脉冲波的一种技术。一般转换后脉波的周期固定,但占空比会随模拟信号的大小而改变。讲多了,下面直接讲重点,如何用C语言实现PWM输出。
STC12C5A60S2单片机通过程序设定工作在八位PAM模式,其占空比与PCA_PWMn(n=0,1下同)寄存器的EPCnL和CCAPn L的值有关。当CL的值小于[EPCnL,CCAPn L]时PWM输出低电平,大于时输出高电平。八位计数器CL不断的从00加一,直到FF再循环,这样就形成了一定占空比的方波,当CL从FF溢出到00时,[EPCnH,CCAPn H]的值自动装载到[EPCnL,CCAPn L]中,我们只要改变[EPCnH,CCAPn H],在下一个周期就会形成新的占空比。要想使用PWM功能,要将CCAPMn寄存器的ECOMn和PWMn位置位。CL和CH的初值都为0(八位(256-256)%256和(256-256)/256)。CCAPn H的值等于=255-255*占空比/100。
主要文件
/********************************************************************
* 文件名 : 12系列PWM输出
* 描述 : 利用12系列自带的PWM输出可调占空比的脉宽
* 创建人 : 严兵,2013年7月21日
***********************************************************************/
#include "fun.h"
/********************************************************************
* 名称 : 外部中断0服务函数
* 功能 : 外部产生中断时,将占空比值减一
* 输入 : 无
* 输出 : 无
***********************************************************************/
void INT0_interrupt() interrupt 0
{
if ( duty_level > 0 )
{
duty_level --;
CCAP0H = 255 - 255 * duty[duty_level] / 100;
}
else
{
duty_level = 10; //PWM调到最大,发光二极管熄灭
CCAP0H = 255 - 255 * duty[duty_level] / 100;
}
}
main()
{
ms_delay(20);
init_port();
init_int();
init_pca();
EA = 1;//开总中断
while(1);
}
FUN.H头文件
#include <intrins.h>
#include <reg51.h> //包含头文件
//定义端口寄存器
sfr P0M0 = 0X93;
sfr P0M1 = 0X94;
sfr P1M0 = 0X91;
sfr P1M1 = 0X92;
sfr P2M0 = 0X95;
sfr P2M1 = 0X96;
sfr P3M0 = 0Xb1;
sfr P3M1 = 0Xb2;
//与PCA0有关的寄存器
sfr CCON = 0xd8; //PCA控制寄存器
sbit CCF0 = CCON^0; //PCA0中断标志位
sbit CR = CCON^6; //运行控制位
sbit CF = CCON^7; //溢出标志
sfr CMOD = 0xd9; //PCA工作模式寄存器
sfr CL = 0xe9;
sfr CH = 0xf9;
sfr CCAPM0 = 0xda;//PCA0寄存器
sfr CCAP0L = 0xea;
sfr CCAP0H = 0xfa;
sfr PCAPWM0 = 0xf2;
#define fosc 11059200L
sbit s1 = P3^2;
unsigned char duty[11] = {0,10,20,30,40,50,60,70,80,90,100};
unsigned char duty_level; //占空比值
/********************************************************************
* 名称 : 外部中断0初始化函数
* 功能 : 初始化外部中断0
* 输入 : 无
* 输出 : 无
***********************************************************************/
void init_int()
{
IT0 = 1;//设置INT0为下降沿触发
EX0 = 1;//允许INT0中断
}
/********************************************************************
* 名称1: I/O初始化函数
* 功能 : 初始化P1I/O
* 输入 : 无
* 输出 : 无
***********************************************************************/
void init_port()
{
P1M1 = 0x00; //P1.3强推挽输出
P1M0 = 0x04;
}
/********************************************************************
* 名称 : PCA初始化函数
* 功能 : 设置PCA模块0的PWM
* 输入 : 无
* 输出 : 无
***********************************************************************/
void init_pca()
{
CCON = 0; //
CL = 0; //(256-256)/256 PCA计数器初值设定,八位PWM模式
CH = 0; //(256-256)%256
CMOD = 0x08; //0000 1000 时钟源为系统时钟,得到PWM的频率(最快) = fosc / 256 = 43.2k,PWM时PCA计数器不需要产生中断,只要一直计数
duty_level = 0; //占空比0%
CCAP0H = 255 - 255 * duty[duty_level] / 100;//根据PWM占空比算捕获计数值
CCAP0L = CCAP0H; //将高位值(CCAP0H)给低位(CCAP0L),这样就可以通过改变高位值来控制低位值,而占空比是根据CL和[EECPOL,CCAP0L]比较得来的
CCAPM0 = 0x42; //0010 0010 上升沿捕获,PWM使能
CR = 1; // 启动PWM
}
/********************************************************************
* 名称 : 延时函数
* 功能 : 延时T*MS
* 输入 : T
* 输出 : 无
***********************************************************************/
void ms_delay(unsigned int t)
{
unsigned int i;
for (t; t > 0; t--) //外层循环t次
for (i = 1320;i > 0; i--) //内层循环110*12次 ,12系列比51快12倍
;
}
|