PCA16位定时器
Posted ReCclay
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PCA16位定时器相关的知识,希望对你有一定的参考价值。
#include "STC15W4K.H" // 包含STC15W4K寄存器定义文件
sbit LED=P0^0;
void main (void)
//步长计算方法:T*(SYSclk/12)
//0.005*(22118400/12) = 2400H
CCAP0L=0; // 给PCA模块0的CCAP0L置初值
CCAP0H=0x24; // 给PCA模块0的CCAP0H 置初值
CCAPM0=0x49; // 设置PCA模块0为16位定时器
EA=1; // 开总中断
CR=1; // 启动定时器
while(1); // 等待中断
void PCA(void) interrupt 7 // 每5ms进入一次PCA中断
unsigned int temp;
temp=(CCAP0H<<8)+CCAP0L+0x2400; // 运算符“+”的优先级大于“<<”
//注意此处有类型提升
CCAP0L=temp; // 取计算结果的低8位
CCAP0H=temp>>8; // 取计算结果的高8位
CCF0=0; // 清 PCA 模块0 中断标志
LED =!LED; // 在P0.0输出脉冲宽度为5ms的方波
#include "STC15W4K.H" // 包含STC15W4K寄存器定义文件
sbit LED_1s=P0^0;
unsigned char Count; // 中断次数变量
void port_mode() // 端口模式
P0M1=0x00; P0M0=0x00;P1M1=0x00; P1M0=0x00;P2M1=0x00; P2M0=0x00;P3M1=0x00; P3M0=0x00;
P4M1=0x00; P4M0=0x00;P5M1=0x00; P5M0=0x00;P6M1=0x00; P6M0=0x00;P7M1=0x00; P7M0=0x00;
void main (void)
port_mode(); // 所有IO口设为准双向弱上拉方式。
Count=200; // 设置Count计数器初值
CMOD=0x80; // #10000000B 空闲模式下停止PCA计数器工作
// 选择PCA时钟源为Fosc/12,禁止PCA计数器溢出时中断
CCON=0; // 清零PCA计数器溢出中断请求标志位CF
// CR = 0, 不允许 PCA 计数器计数,清零PCA 各模块中断请求标志位CCFn
CL=0; // 清零PCA 计数器
CH=0;
CCAP0L=0; // 给PCA模块0的CCAP0L置初值
CCAP0H=0x24; // 给PCA模块0的CCAP0H 置初值
CCAPM0=0x49; // 设置PCA模块0为16位定时器,ECCF0=1允许PCA模块0中断
// 当[CH,CL]=[CCAP0H,CCAP0L]时,CCF0=1,产生中断请求
EA=1; // 开整个单片机所有中断共享的总中断控制位
CR=1; // 启动PCA计数器(CH,CL)计数
while(1); // 等待中断
void PCA(void) interrupt 7 //PCA中断服务程序
// 每5ms中断一次
union //定义一个联合,以进行16位加法
unsigned int num;
struct // 在联合中定义一个结构
unsigned char Hi,Lo;
Result;
temp;
temp.num=(unsigned int)(CCAP0H<<8)+CCAP0L+0x2400;
CCAP0L=temp.Result.Lo; // 取计算结果的低8位
CCAP0H=temp.Result.Hi; // 取计算结果的高8位
CCF0=0; // 清 PCA 模块0 中断标志
Count--; // 修改中断计数
if (Count==0)
Count=200; // 恢复中断计数初值
LED_1s =!LED_1s; // 在P0.0输出脉冲宽度为1秒钟的方波(0.5Hz)
共用体嵌套在结构体内简直6的一批。
原理呢?
这么来看的话,其实也就很好理解了,num是int类型的,也就决定了这个共用体占有两个字节的内存,恰好它和一个结构体的两个char成员共用这块内存,那第一个就可以表示高字节。第二个就可以表示低字节。
但是
多字节变量的字节序取决于单片机架构和编译器,并非是固定的。所以使用这种嵌套的方法的话,一定要清楚字节。
下面利用定时器T0作脉冲源
#include "STC15W4K.H" // 包含STC15W4K寄存器定义文件
sbit LED_1s=P0^0;
unsigned char Count=200; // 中断次数变量
void port_mode() // 端口模式
P0M1=0x00; P0M0=0x00;P1M1=0x00; P1M0=0x00;P2M1=0x00; P2M0=0x00;P3M1=0x00; P3M0=0x00;
P4M1=0x00; P4M0=0x00;P5M1=0x00; P5M0=0x00;P6M1=0x00; P6M0=0x00;P7M1=0x00; P7M0=0x00;
void main (void)
port_mode(); // 所有IO口设为准双向弱上拉方式。
// 初始化定时器T0为8位自动重装方式
TMOD=0x02; // 设置T0为8位自动重装方式
TH0=246; // 来256-246=10个脉冲就中断
TL0=246; // 来256-246=10个脉冲就中断
TR0=1; // 启动定时器0
// 初始化PCA模块0为16位定时器方式
CMOD=0x84; // #10000100B 空闲模式下停止PCA计数器工作
// 选择PCA时钟源为T0溢出信号,禁止PCA计数器溢出时中断
CCON=0; // 清零PCA计数器溢出中断请求标志位CF
// CR = 0, 不允许 PCA 计数器计数,清零PCA 各模块中断请求标志位CCFn
CL=0; // 清零PCA 计数器
CH=0;
CCAP0L=0x99; // 给PCA模块0的CCAP0L置初值
CCAP0H=0x03; // 给PCA模块0的CCAP0H 置初值
CCAPM0=0x49; // 设置PCA模块0为16位定时器,ECCF0=1允许PCA模块0中断
// 当[CH,CL]=[CCAP0H,CCAP0L]时,CCF0=1,产生中断请求
EA=1; // 开整个单片机所有中断共享的总中断控制位
CR=1; // 启动PCA计数器(CH,CL)计数
// INT_CLKO =INT_CLKO|0x01; //允许T0/P3.5时钟输出,调试观察TO是否正常
while(1); // 等待中断
void PCA(void) interrupt 7 //PCA中断服务程序
// 每5ms中断一次
union //定义一个联合,以进行16位加法
unsigned int num;
struct // 在联合中定义一个结构
unsigned char Hi,Lo;
Result;
temp;
temp.num=(unsigned int)(CCAP0H<<8)+CCAP0L+0x399;
CCAP0L=temp.Result.Lo; // 取计算结果的低8位
CCAP0H=temp.Result.Hi; // 取计算结果的高8位
CCF0=0; // 清 PCA 模块0 中断标志
Count--; // 修改中断计数
if (Count==0)
Count=200; // 恢复中断计数初值
LED_1s =!LED_1s; // 在P0.0输出脉冲宽度为1秒钟的方波(0.5Hz)
理解这个程序务必先理解好,所谓的配置寄存器达到定时器的原理:
PCA的计数器每隔时钟源分之1就加1,直到和比较寄存器的值(CCAPnH和CCAPnL相同)就产生PCA中断,在中断中再对比较寄存器加相同的步值,以此做定时器的功能。
要定时5ms,使用八位自动重装载模式,10个脉冲就溢出,计数一个脉冲对应的时间为12/SYSclk,是个脉冲对应时间为120/SYSclk,那么对应的脉冲频率就是SYSclk/120,也就是120分频了。
实际计算一下,22118400/120*0.05 = 921.6=0x0399
以上是关于PCA16位定时器的主要内容,如果未能解决你的问题,请参考以下文章