基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用

基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用

  • STC12C5A60S2系列1T 8051单片机管脚图
  • STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置
  • STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍
  • STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的结构
  • STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的各种不同工作模式介绍
  • 基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的特殊功能寄存器列表
    • 基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)模块用到的特殊功能寄存器
      • PCA辅助寄存器AUXR1
      • PCA工作模式寄存器CMOD
      • PCA工作模式寄存器CCON
      • PCA比较/捕获寄存器CCAPM0和CCAPM1
      • PCA的16位定时器/计数器 —— 高八位CH和低八位CL
      • PCA捕获/比较寄存器高八位CCAPnH和低八位CCAPnL
      • PCA的PWM寄存器PCA_PWM0和PCA_PWM1
      • 利用晶振频率为12MHz的STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块0从P1.3引脚输出频率为200Hz且占空比为40%的矩形波 可根据以下CCP/PCA/PWM模块的脉冲宽度调制模式来编写程序
      • 利用晶振频率为12MHz的STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块0从P1.3引脚输出频率为200Hz且占空比可调的矩形波 可根据以下CCP/PCA/PWM模块的脉冲宽度调制模式来编写程序![在这里插入图片描述](https://img-blog.csdnimg.cn/3d3287492e2340959a5c40d59a81b247.jpg)![在这里插入图片描述](https://img-blog.csdnimg.cn/a860de5af3594e38aae903d822a3dc94.jpg)![在这里插入图片描述](https://img-blog.csdnimg.cn/470345c725034aad991d0c8c471f79f9.jpg)![在这里插入图片描述](https://img-blog.csdnimg.cn/e7dccf59143c41eb9aa01d538836329f.jpg)
      • 利用晶振频率为12MHz的STC12C5A60S2系列1T 8051单片机定时器0的16位定时器模式1定时计数溢出作为可编程计数阵列CCP/PCA/PWM模块0的时钟源输入来从P1.3引脚输出频率为1KHz且占空比可调的矩形波 可根据以下CCP/PCA/PWM模块的脉冲宽度调制模式来编写程序

STC12C5A60S2系列1T 8051单片机管脚图

基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用_第1张图片基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用_第2张图片

STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置

基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用_第3张图片

STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍

基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用_第4张图片基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用_第5张图片

STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的结构

基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用_第6张图片基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用_第7张图片

STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的各种不同工作模式介绍

基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用_第8张图片基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用_第9张图片基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用_第10张图片基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用_第11张图片基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用_第12张图片

基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的特殊功能寄存器列表

基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用_第13张图片

基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)模块用到的特殊功能寄存器

PCA辅助寄存器AUXR1

基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用_第14张图片
作用:用来设置STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的单片机引脚

PCA工作模式寄存器CMOD

基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用_第15张图片
作用:用来设置STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块以下功能
(1)、空闲情况下是否停止CCP/PCA/PWM模块计数
(2)、CCP/PCA/PWM模块计数脉冲时钟源选择 (3)、CCP/PCA/PWM模块计数溢出中断使能

PCA工作模式寄存器CCON

基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用_第16张图片
作用:用来设置STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块以下功能
(1)、CCP/PCA/PWM模块计数溢出标志位
(2)、CCP/PCA/PWM模块运行
(3)、CCP/PCA/PWM模块0中断标志位
(4)、CCP/PCA/PWM模块1中断标志位

PCA比较/捕获寄存器CCAPM0和CCAPM1

基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用_第17张图片基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用_第18张图片
作用:用来设置STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块以下功能
(1)、CCP/PCA/PWM模块0允许比较器功能控制
(2)、CCP/PCA/PWM模块0上升沿捕获控制
(3)、CCP/PCA/PWM模块0下降沿捕获控制
(4)、CCP/PCA/PWM模块0匹配工作模式寄存器CCON中断标志位控制
(5)、CCP/PCA/PWM模块0匹配CCPn寄存器引脚电平翻转控制
(6)、CCP/PCA/PWM模块0脉冲宽度调制模式
(7)、CCP/PCA/PWM模块0使能工作模式寄存器CCON中断标志位控制
(8)、CCP/PCA/PWM模块1允许比较器功能控制
(9)、CCP/PCA/PWM模块1上升沿捕获控制
(10)、CCP/PCA/PWM模块1下降沿捕获控制
(11)、CCP/PCA/PWM模块1匹配工作模式寄存器CCON中断标志位控制
(12)、CCP/PCA/PWM模块1匹配CCPn寄存器引脚电平翻转控制
(13)、CCP/PCA/PWM模块1脉冲宽度调制模式
(14)、CCP/PCA/PWM模块1使能工作模式寄存器CCON中断标志位控制

PCA的16位定时器/计数器 —— 高八位CH和低八位CL

基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用_第19张图片
作用:作为CCP/PCA/PWM模块0或CCP/PCA/PWM模块1的计数器进行脉冲计数

PCA捕获/比较寄存器高八位CCAPnH和低八位CCAPnL

基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用_第20张图片
作用:作为捕获或比较时 用于CCP/PCA/PWM模块0或CCP/PCA/PWM模块1的计数器进行脉冲计数 作为脉冲宽度调制时 用于CCP/PCA/PWM模块0或CCP/PCA/PWM模块1的高八位CCAPnH脉冲计数重载给低八位CCAPnL进行脉冲计数控制脉冲宽度调制

PCA的PWM寄存器PCA_PWM0和PCA_PWM1

基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用_第21张图片
作用:组成CCP/PCA/PWM模块0或CCP/PCA/PWM模块1的PWM寄存器内部累计计数的9位数据

利用晶振频率为12MHz的STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块0从P1.3引脚输出频率为200Hz且占空比为40%的矩形波 可根据以下CCP/PCA/PWM模块的脉冲宽度调制模式来编写程序

基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用_第22张图片基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用_第23张图片基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用_第24张图片基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用_第25张图片

#include <STC12C5A60S2.h>
void PortModeSet();//端口模式设置函数
void PcaInit();//CCP/PCA/PWM模块初始化函数
void Timer0Init();//定时0初始化函数
 void main()
{
  PortModeSet();//端口模式设置函数
  PcaInit();//CCP/PCA/PWM模块初始化函数
  Timer0Init();//定时0初始化函数
  while(1);
 }
 void PortModeSet()//端口模式设置函数
{  
  P0M1 = 0x00;
  P0M0 = 0x00;
  P1M1 = 0x00;
  P1M0 = 0x00;
  P2M1 = 0x00;
  P2M0 = 0x00;
  P3M1 = 0x00;
  P3M0 = 0x00;
  P4M1 = 0x00;
  P4M0 = 0x00;
 }
 void PcaInit()//CCP/PCA/PWM模块初始化函数
{
  CMOD = 0x04 ;//CCP/PCA/PWM模块空闲模式下CCP/PCA/PWM模块计数器继续工作 选定时器T0溢出脉冲作为CCP/PCA/PWM模块时钟源 禁止CCP/PCA/PWM模块溢出中断使能
  CCON = 0x00;//CCP/PCA/PWM模块计数溢出标志位清0 运行位清0 中断标志位清0
  CCAPM0 = 0x42;//CCP/PCA/PWM模块0允许比较器功能控制 不允许边沿捕获控制 不匹配工作模式寄存器CCON中断标志位控制 不匹配CCPn寄存器引脚电平翻转控制 输出脉冲宽度调制模式 不使能工作模式寄存器CCON中断标志位控制
  CH = 0x00;//CCP/PCA/PWM模块16位计数器高八位计数寄存器脉冲计数清0
  CL = 0x00;//CCP/PCA/PWM模块16位计数器低八位计数寄存器脉冲计数清0
  CCAP0H = 0x00;//同下
  CCAP0L = 0x00;//CCP/PCA/PWM模块
  CR = 1;//启动CCP/PCA/PWM模块16计数器
 }
 void Timer0Init()//定时器0初始化函数
{
  AUXR = 0x80;//将定时器/计数器设置为1T模式 不用分频 
  TMOD = 0x02;//选定时器/计数器为定时器0 工作模式为模式2的8位自动重装计数 即溢出时将TH0存放的脉冲计数自动装入TL0
  TH0 = 0x16;//由于选定时器/计数器为1T模式不用分频定时器0 工作模式为模式2的8位自动重装计数 因此先根据PWM频率=CCP/PCA/PWM模块时钟源频率/256求出CCP/PCA/PWM模块时钟源频率 即200Hz=CCP/PCA/PWM模块时钟源频率/256 求CCP/PCA/PWM模块时钟源频率=51200Hz 再根据定时器初值(定时计数初值)=2^n-(晶振频率/几分频/定时频率)求出定时器初值(定时计数初值) 即定时器初值(定时计数初值)=2^8-(12MHz/1/51200Hz)=256-(12000000Hz/51200Hz)=256-234=22=0x16
  TL0 = 0x16;//同上
  EA = 1;//打开定时器中断总开关
  TR0 = 1;//启动定时器0
 } 

利用晶振频率为12MHz的STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块0从P1.3引脚输出频率为200Hz且占空比可调的矩形波 可根据以下CCP/PCA/PWM模块的脉冲宽度调制模式来编写程序基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用_第26张图片基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用_第27张图片基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用_第28张图片基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用_第29张图片

#include <STC12C5A60S2.h>
#define uchar unsigned char//自定义无符号字符型为uchar
#define uint unsigned int//自定义无符号整数型为uint
#define KeyPressDeshakeTime 10//自定义按键按下消抖时间为10ms
#define KeyLongPressDelayTime 500//自定义按键长按延时时间为500ms
#define KeyLongPressIntervalChangeTime 25//自定义按键长按间隔变化时间为25ms
uchar AddKeyLockFlag;//声明增加按键锁定标志位变量
uchar DecKeyLockFlag;//声明减少按键锁定标志位变量
uchar KeyNumber = 0;//定义按键键值为0
uchar AddKeyLongPressAddIntervalTime;//声明增加按键长按连增间隔时间变量
uchar DecKeyLongPressDecIntervalTime;//声明减少按键长按连减间隔时间变量
uint AddKeyPressDelayTime;//声明增加按键按下延时时间变量
uint DecKeyPressDelayTime;//声明减少按键按下延时时间变量
sbit AddKey = P2^0;//位定义增加按键为单片机P2.0引脚
sbit DecKey = P2^1;//位定义减少按键为单片机P2.1引脚
uchar PwmValue;//声明脉宽调制值变量
void PortModeSet();//端口模式设置函数
void PcaInit();//CCP/PCA/PWM模块初始化函数
void Timer0Init();//定时器0初始化函数
void Timer1Init();//定时器1初始化函数
void PwmDutyCycleSet();//脉冲宽度占空比设置函数
 void main()//主函数
{
  PortModeSet();//端口模式设置函数
  PcaInit();//CCP/PCA/PWM模块初始化函数
  Timer0Init();//定时器0初始化函数
  Timer1Init();//定时器1初始化函数
  while(1)
 {
   PwmDutyCycleSet();//脉冲宽度占空比设置函数
  }
 }
 void PortModeSet()//端口模式设置函数
{  
  P0M1 = 0x00;
  P0M0 = 0x00;
  P1M1 = 0x00;
  P1M0 = 0x00;
  P2M1 = 0x00;
  P2M0 = 0x00;
  P3M1 = 0x00;
  P3M0 = 0x00;
  P4M1 = 0x00;
  P4M0 = 0x00;
 }
 void PcaInit()//CCP/PCA/PWM模块初始化函数
{
  CMOD = 0x84 ;//CCP/PCA/PWM模块空闲模式下CCP/PCA/PWM模块计数器停止工作 选定时器T0溢出脉冲作为CCP/PCA/PWM模块时钟源 禁止CCP/PCA/PWM模块溢出中断使能
  CCON = 0x00;//CCP/PCA/PWM模块计数溢出标志位清0 运行位清0 中断标志位清0
  CCAPM0 = 0x42;//CCP/PCA/PWM模块0允许比较器功能控制 不允许边沿捕获控制 不匹配工作模式寄存器CCON中断标志位控制 不匹配CCPn寄存器引脚电平翻转控制 输出脉冲宽度调制模式 不使能工作模式寄存器CCON中断标志位控制
  CH = 0x00;//CCP/PCA/PWM模块16位计数器高八位计数寄存器脉冲计数清0
  CL = 0x00;//CCP/PCA/PWM模块16位计数器低八位计数寄存器脉冲计数清0
  CCAP0H = 0x00;//同下
  CCAP0L = 0x00;//CCP/PCA/PWM模块
  CR = 1;//启动CCP/PCA/PWM模块16计数器
 }   
 void Timer0Init()//定时器0初始化函数
{
  AUXR = 0x80;//将定时器/计数器设置为1T模式 不用分频 
  TMOD = 0x02;//选定时器/计数器为定时器0 工作模式为模式2的8位自动重装计数 即溢出时将TH0存放的脉冲计数自动装入TL0
  TH0 = 0x16;//由于选定时器/计数器为1T模式不用分频定时器0 工作模式为模式2的8位自动重装计数 因此先根据PWM频率=CCP/PCA/PWM模块时钟源频率/256求出CCP/PCA/PWM模块时钟源频率 即200Hz=CCP/PCA/PWM模块时钟源频率/256 求CCP/PCA/PWM模块时钟源频率=51200Hz 再根据定时器初值(定时计数初值)=2^n-(晶振频率/几分频/定时频率)求出定时器初值(定时计数初值) 即定时器初值(定时计数初值)=2^8-(12MHz/1/51200Hz)=256-(12000000Hz/51200Hz)=256-234=22=0x16
  TL0 = 0x16;//同上
  EA = 1;//打开定时器中断总开关
  TR0 = 1;//启动定时器0
 }
 /*****关于通过特殊功能寄存器AUXR设定定时器/计数器模式为1T或12T模式不需分频或需12分频8051系列单片机定时器初值(定时计数初值)计算的知识点*****/
  /****
  时钟周期(又称振荡周期):单片机晶振频率的倒数 例:单片机晶振频率12MHz 则时钟周期=[1/(12*10^6)Hz]s=0.000000083s=0.000083ms=0.083us
  机器周期:单片机执行一条指令过程中需要完成一个基本操作(如:取指、译码、执行等基本操作)所需的时间 8051系列单片机的一个机器周期由6个S周期(状态周期)组成 一个时钟周期定义为一个节拍(用P表示) 二个节拍定义为一个状态周期(用S表示) 那么8051单片机的机器周期由6个状态周期组成 也就是说一个机器周期=6个状态周期=12个时钟周期=[12x[1/(12*10^6)Hz]s]s=0.000001s=0.001ms=1us
  指令周期:单片机取出一条指令且执行完这条指令所需的时间
  以上三者间的关系:指令周期>机器周期>时钟周期
  一、通过特殊功能寄存器AUXR设定定时器/计数器模式为12T模式需12分频8051系列单片机定时器初值(定时计数初值)计算步骤如下(以单片机晶振频率为12MHz 定时器0工作模式为16位定时模式1 需要定时1ms来计算):
  1、一个机器周期=12个时钟周期=12乘以单片机晶振频率的倒数=12*[1/(12*10^6)Hz]s=0.000001s=0.001ms=1us
  2、定时时间=定时计数*一个机器周期 1ms=定时计数*1us 定时计数=1ms/1us=1000us/1us=1000次
  3、定时器初值(定时计数初值)=2^n-定时计数 n为几位定时器 此处n=16 则定时器初值(定时计数初值)=2^16-1000=65536-1000=64536 把64536转化成十六进制 拆开成高八位和低八位 高八位放TH0=0xfc或(65536-64536)/256 低八位放TL0=0x18或(65536-64536)%256
  二、以下是通过特殊功能寄存器AUXR设定定时器/计数器模式为1T或12T模式不需分频或需12分频8051系列单片机定时器初值(定时计数初值)计算步骤如下(以单片机晶振频率为12MHz 定时器0工作模式为16位定时模式1 需要定时1ms来计算):
  4、综合公式:定时器初值(定时计数初值)=2^n-(晶振频率/几分频/定时频率) n为几位定时器 该公式常用于脉冲宽度调制中运算 例如:利用8051系列单片机晶振频率为12MHz的定时器0的16位定时模式1来产生1KHz方波脉冲 由此可知:定时时间=1/定时频率=1/1000Hz=0.001s=1ms=1000us 进而可得:定时器初值(定时计数初值)=2^n-(晶振频率/几分频/定时频率)=2^16-(12MHz/12/1KHz)=2^16-(12*10^6)Hz/12/1000Hz)=65536-1000=64536 把64536转化成十六进制 拆开成高八位和低八位 高八位放TH0=0xfc或(65536-64536)/256或Value >> 8 低八位放TL0=0x18或(65536-64536)%256或=Value 
  5、TH0 = Value >> 8;TL0 = Value;该两句代码解释如下:
  (1)、TH0 = Value >> 8相当于TH0 = (65536-10000)/256=55536/256=216.9375 分析:65536-10000=55536转化成二进制为11011000 11110000 55536/256=216.9375转化成二进制为11011000 由此可看出Value为(65536-10000)=55536的二进制数11011000 11110000右移8位就可以得到55536/256=216.9375的二进制数11011000
  (2)、TL0 = Value相当于TL0 = (65536-10000)%256=55536%256=240 分析:65536-10000=55536转化成二进制为11011000 11110000 55536%256=240转化成二进制为11110000 由此可看出Value为(65536-10000)=55536的二进制数11011000 11110000取低8位就可以得到55536%256=240的二进制数11110000
  ****/
 void Timer1Init(void)//定时器1定时2ms初始化函数 晶振为12MHz
{
  AUXR = 0x00;//将定时器/计数器设置为12T模式 用12分频 
  TMOD &= 0x0f;//设定定时器/计数器工作模式清0
  TMOD |= 0x10;//设定定时器/计数器为定时器 工作模式为16位定时器1模式1
  TH1 = 0xf8;//设定定时器1计数高8位初值
  TL1 = 0x30;//设定定时器1计数低8位初值
  TF1 = 0;//定时器1溢出中断标志位清0
  ET1 = 1;//打开定时器1中断开关
  EA = 1;//打开定时器中断总开关
  TR1 = 1//打开定时器1开关
 } 
 void Timer1(void) interrupt 3//定时器1定时2ms中断函数 晶振为12MHz
{
  TR1 = 0;//关闭定时器1
  KeyScan();//按键扫描函数
  TH1 = 0xf8;//设定定时器1计数高8位初值
  TL1 = 0x30;//设定定时器1计数低8位初值
  TR1 = 1;//打开定时器1
 }
 void KeyScan(void)//按键扫描函数 该函数放在定时器定时2ms的中断函数中扫描
{
  if(AddKey)//如果增加按键没按下或弹起
 {
   AddKeyLockFlag = 0;//增加按键锁定标志位清0
   AddKeyPressDelayTime = 0;//增加按键按下延时时间清0
  }   
  else if(!AddKeyLockFlag)//如果增加按键锁定标志位置1 即增加按键按下
 {
   AddKeyPressDelayTime++;//增加按键按下延时时间自加
   if(AddKeyPressDelayTime > KeyPressDeshakeTime)//如果增加按键按下延时时间大于按键按下消抖时间
  {
    AddKeyPressDelayTime = 0;//增加按键按下延时时间清0
    KeyNumber = 1;//按键键值置1 此处是单击增加 可赋给swicth()语句中的变量来对数值单击增加
    AddKeyLockFlag = 1;//增加按键锁定标志位置1
   }
  }
  else if(AddKeyPressDelayTime < KeyLongPressDelayTime)//如果增加按键按下延时时间小于按键长按延时时间
 {
   AddKeyPressDelayTime++;//增加按键按下延时时间自加
  }
  else//如果增加按键按下延时时间大于按键长按延时时间
 {
   AddKeyLongPressAddIntervalTime++;//增加按键长按连增间隔时间自加
   if(AddKeyLongPressAddIntervalTime > KeyLongPressIntervalChangeTime)//如果增加按键长按连增间隔时间大于按键长按间隔变化时间
  {
     AddKeyLongPressAddIntervalTime = 0;//增加按键长按连增间隔时间清0
     KeyNumber = 1;//按键键值置1 此处是连击增加 可赋给swicth()语句中的变量来对数值连击增加
   }
  }   
  if(DecKey)//如果减少按键没按下或弹起
 {
   DecKeyLockFlag = 0;//减少按键锁定标志位清0
   DecKeyPressDelayTime = 0;//减少按键按下延时时间清0
  }   
  else if(!DecKeyLockFlag)//如果减少按键锁定标志位置1 即减少按键按下
 {
   DecKeyPressDelayTime++;//减少按键按下延时时间自加
   if(DecKeyPressDelayTime > KeyPressDeshakeTime)//如果减少按键按下延时时间大于按键按下消抖时间
  {
    DecKeyPressDelayTime = 0;//减少按键按下延时时间清0
    KeyNumber = 2;//按键键值置2 此处是单击减少 可赋给swicth()语句中的变量来对数值单击减少
    DecKeyLockFlag = 1;//减少按键锁定标志位置1
   }
  }
  else if(DecKeyPressDelayTime < KeyLongPressDelayTime)//如果减少按键按下延时时间小于按键长按延时时间
 {
   DecKeyPressDelayTime++;//减少按键按下延时时间自加
  }
  else//如果减少按键按下延时时间大于按键长按延时时间
 {
   DecKeyLongPressDecIntervalTime++;//减少按键长按连减间隔时间自加
   if(DecKeyLongPressDecIntervalTime > KeyLongPressIntervalChangeTime)//如果减少按键长按连减间隔时间大于按键长按间隔变化时间
  {
    DecKeyLongPressDecIntervalTime = 0;//减少按键长按连减间隔时间清0
    KeyNumber = 2;//按键键值置2 此处是连击减少 可赋给swicth()语句中的变量来对数值连击减少
    }
   }
 }
 void PwmDutyCycleSet()//脉冲宽度占空比设置函数
{
  switch(KeyNumber)//按键类型筛选位
 {
   case 1 ://增加按键单击、长按触发位
           PwmValue++;//脉冲宽度值自加
           if(PwmValue > 255)//如果脉冲宽度值大于255
          {
            PwmValue = 255;//脉冲宽度值等于255
           }
           CCAP0H = CCAP0L = PwmValue;//脉冲宽度值赋给CCP/PCA/PWM模块0高低八位捕获/比较寄存器
           KeyNumber = 0;//按键键值清0
           break;//跳出
   case 2 ://减少按键单击、长按触发位
           PwmValue--;//脉冲宽度值自减
           if(PwmValue < 0)//如果脉冲宽度值小于
          {
            PwmValue = 0;//脉冲宽度值清0
           }
           CCAP0H = CCAP0L = PwmValue;//脉冲宽度值赋给CCP/PCA/PWM模块0高低八位捕获/比较寄存器
           KeyNumber = 0;//按键键值清0
           break;//跳出
   default:break;//跳出
  }
 }

利用晶振频率为12MHz的STC12C5A60S2系列1T 8051单片机定时器0的16位定时器模式1定时计数溢出作为可编程计数阵列CCP/PCA/PWM模块0的时钟源输入来从P1.3引脚输出频率为1KHz且占空比可调的矩形波 可根据以下CCP/PCA/PWM模块的脉冲宽度调制模式来编写程序



 
 /*****关于通过特殊功能寄存器AUXR设定定时器/计数器模式为1T或12T模式不需分频或需12分频8051系列单片机定时器初值(定时计数初值)计算的知识点*****/
  /****
  时钟周期(又称振荡周期):单片机晶振频率的倒数 例:单片机晶振频率12MHz 则时钟周期=[1/(12*10^6)Hz]s=0.000000083s=0.000083ms=0.083us
  机器周期:单片机执行一条指令过程中需要完成一个基本操作(如:取指、译码、执行等基本操作)所需的时间 8051系列单片机的一个机器周期由6个S周期(状态周期)组成 一个时钟周期定义为一个节拍(用P表示) 二个节拍定义为一个状态周期(用S表示) 那么8051单片机的机器周期由6个状态周期组成 也就是说一个机器周期=6个状态周期=12个时钟周期=[12x[1/(12*10^6)Hz]s]s=0.000001s=0.001ms=1us
  指令周期:单片机取出一条指令且执行完这条指令所需的时间
  以上三者间的关系:指令周期>机器周期>时钟周期
  一、以下是通过特殊功能寄存器AUXR设定定时器/计数器模式为12T模式需12分频8051系列单片机定时器初值(定时计数初值)计算步骤如下(以单片机晶振频率为12MHz 定时器0工作模式为16位定时模式1 需要定时1ms来计算):
  1、一个机器周期=12个时钟周期=12乘以单片机晶振频率的倒数=12*[1/(12*10^6)Hz]s=0.000001s=0.001ms=1us
  2、定时时间=定时计数*一个机器周期 1ms=定时计数*1us 定时计数=1ms/1us=1000us/1us=1000次
  3、定时器初值(定时计数初值)=2^n-定时计数 n为几位定时器 此处n=16 则定时器初值(定时计数初值)=2^16-1000=65536-1000=64536 把64536转化成十六进制 拆开成高八位和低八位 高八位放TH0=0xfc或(65536-64536)/256 低八位放TL0=0x18或(65536-64536)%256
  二、以下是通过特殊功能寄存器AUXR设定定时器/计数器模式为1T或12T模式不需分频或需12分频8051系列单片机定时器初值(定时计数初值)计算步骤如下(以单片机晶振频率为12MHz 定时器0工作模式为16位定时模式1 需要定时1ms来计算):
  4、综合公式:定时器初值(定时计数初值)=2^n-(晶振频率/几分频/定时频率) n为几位定时器 该公式常用于脉冲宽度调制中运算 例如:利用8051系列单片机晶振频率为12MHz的定时器0的16位定时模式1来产生1KHz方波脉冲 由此可知:定时时间=1/定时频率=1/1000Hz=0.001s=1ms=1000us 进而可得:定时器初值(定时计数初值)=2^n-(晶振频率/几分频/定时频率)=2^16-(12MHz/12/1KHz)=2^16-(12*10^6)Hz/12/1000Hz)=65536-1000=64536 把64536转化成十六进制 拆开成高八位和低八位 高八位放TH0=0xfc或(65536-64536)/256或Value >> 8 低八位放TL0=0x18或(65536-64536)%256或=Value 
  5、TH0 = Value >> 8;TL0 = Value;该两句代码解释如下:
  (1)、TH0 = Value >> 8相当于TH0 = (65536-10000)/256=55536/256=216.9375 分析:65536-10000=55536转化成二进制为11011000 11110000 55536/256=216.9375转化成二进制为11011000 由此可看出Value为(65536-10000)=55536的二进制数11011000 11110000右移8位就可以得到55536/256=216.9375的二进制数11011000
  (2)、TL0 = Value相当于TL0 = (65536-10000)%256=55536%256=240 分析:65536-10000=55536转化成二进制为11011000 11110000 55536%256=240转化成二进制为11110000 由此可看出Value为(65536-10000)=55536的二进制数11011000 11110000取低8位就可以得到55536%256=240的二进制数11110000
  ****/
 void Timer0Init()//定时器0定时1ms初始化函数
{
  AUXR = 0x80;//将定时器/计数器设置为1T模式 不用用分频 
  TMOD = 0x01;//选定时器/计数器为定时器0 工作模式为16定时器模式1 
  TH0 = 0xff;//由于选定时器/计数器为1T模式 不用分频定时器0 因此先根据PWM频率=CCP/PCA/PWM模块时钟源频率/256求出CCP/PCA/PWM模块时钟源频率 即1KHz=1000Hz=CCP/PCA/PWM模块时钟源频率/256 求CCP/PCA/PWM模块时钟源频率=256000Hz 再根据定时器初值(定时计数初值)=2^n-(晶振频率/几分频/定时频率)求出定时器初值(定时计数初值) 即定时器初值(定时计数初值)=2^16-(12MHz/1/256000Hz)=65536-(12000000Hz/1/256000Hz)=65536-(12000000Hz/256000Hz)=65536-47=65489 把65489转化成十六进制 拆开成高八位和低八位 高八位放TH0=0xff或(65536-65489)/256或Value >> 8 低八位放TL0=0xfc或(65536-65489)%256或=Value 
  TL0 = 0xd1;//同上
  TF0 = 0;//定时器0溢出中断标志位清0
  ET0 = 1;//打开定时器0中断开关
  EA = 1;//打开定时器中断总开关
  TR0 = 1;//启动定时器0
 }
 void Timer1Init(void)//定时器1定时2ms初始化函数 晶振为12MHz
{
  AUXR = 0x00;//将定时器/计数器设置为12T模式 用12分频 
  TMOD &= 0x0f;//设定定时器/计数器工作模式清0
  TMOD |= 0x10;//设定定时器/计数器为定时器 工作模式为16位定时器1模式1
  TH1 = 0xf8;//设定定时器1计数高8位初值
  TL1 = 0x30;//设定定时器1计数低8位初值
  TF1 = 0;//定时器1溢出中断标志位清0
  ET1 = 1;//打开定时器1中断开关
  EA = 1;//打开定时器中断总开关
  TR1 = 1//打开定时器1开关
 } 
 void Timer1(void) interrupt 3//定时器1定时2ms中断函数 晶振为12MHz
{
  TR1 = 0;//关闭定时器1
  KeyScan();//按键扫描函数
  TH1 = 0xf8;//设定定时器1计数高8位初值
  TL1 = 0x30;//设定定时器1计数低8位初值
  TR1 = 1;//打开定时器1
 }
 void KeyScan(void)//按键扫描函数 该函数放在定时器定时2ms的中断函数中扫描
{
  if(AddKey)//如果增加按键没按下或弹起
 {
   AddKeyLockFlag = 0;//增加按键锁定标志位清0
   AddKeyPressDelayTime = 0;//增加按键按下延时时间清0
  }   
  else if(!AddKeyLockFlag)//如果增加按键锁定标志位置1 即增加按键按下
 {
   AddKeyPressDelayTime++;//增加按键按下延时时间自加
   if(AddKeyPressDelayTime > KeyPressDeshakeTime)//如果增加按键按下延时时间大于按键按下消抖时间
  {
    AddKeyPressDelayTime = 0;//增加按键按下延时时间清0
    KeyNumber = 1;//按键键值置1 此处是单击增加 可赋给swicth()语句中的变量来对数值单击增加
    AddKeyLockFlag = 1;//增加按键锁定标志位置1
   }
  }
  else if(AddKeyPressDelayTime < KeyLongPressDelayTime)//如果增加按键按下延时时间小于按键长按延时时间
 {
   AddKeyPressDelayTime++;//增加按键按下延时时间自加
  }
  else//如果增加按键按下延时时间大于按键长按延时时间
 {
   AddKeyLongPressAddIntervalTime++;//增加按键长按连增间隔时间自加
   if(AddKeyLongPressAddIntervalTime > KeyLongPressIntervalChangeTime)//如果增加按键长按连增间隔时间大于按键长按间隔变化时间
  {
     AddKeyLongPressAddIntervalTime = 0;//增加按键长按连增间隔时间清0
     KeyNumber = 1;//按键键值置1 此处是连击增加 可赋给swicth()语句中的变量来对数值连击增加
   }
  }   
  if(DecKey)//如果减少按键没按下或弹起
 {
   DecKeyLockFlag = 0;//减少按键锁定标志位清0
   DecKeyPressDelayTime = 0;//减少按键按下延时时间清0
  }   
  else if(!DecKeyLockFlag)//如果减少按键锁定标志位置1 即减少按键按下
 {
   DecKeyPressDelayTime++;//减少按键按下延时时间自加
   if(DecKeyPressDelayTime > KeyPressDeshakeTime)//如果减少按键按下延时时间大于按键按下消抖时间
  {
    DecKeyPressDelayTime = 0;//减少按键按下延时时间清0
    KeyNumber = 2;//按键键值置2 此处是单击减少 可赋给swicth()语句中的变量来对数值单击减少
    DecKeyLockFlag = 1;//减少按键锁定标志位置1
   }
  }
  else if(DecKeyPressDelayTime < KeyLongPressDelayTime)//如果减少按键按下延时时间小于按键长按延时时间
 {
   DecKeyPressDelayTime++;//减少按键按下延时时间自加
  }
  else//如果减少按键按下延时时间大于按键长按延时时间
 {
   DecKeyLongPressDecIntervalTime++;//减少按键长按连减间隔时间自加
   if(DecKeyLongPressDecIntervalTime > KeyLongPressIntervalChangeTime)//如果减少按键长按连减间隔时间大于按键长按间隔变化时间
  {
    DecKeyLongPressDecIntervalTime = 0;//减少按键长按连减间隔时间清0
    KeyNumber = 2;//按键键值置2 此处是连击减少 可赋给swicth()语句中的变量来对数值连击减少
    }
   }
 }
 void PwmDutyCycleSet()//脉冲宽度占空比设置函数
{
  switch(KeyNumber)//按键类型筛选位
 {
   case 1 ://增加按键单击、长按触发位
           PwmValue++;//脉冲宽度值自加
           if(PwmValue > 255)//如果脉冲宽度值大于255
          {
            PwmValue = 255;//脉冲宽度值等于255
           }
           CCAP0H = CCAP0L = PwmValue;//脉冲宽度值赋给CCP/PCA/PWM模块0高低八位捕获/比较寄存器
           KeyNumber = 0;//按键键值清0
           break;//跳出
   case 2 ://减少按键单击、长按触发位
           PwmValue--;//脉冲宽度值自减
           if(PwmValue < 0)//如果脉冲宽度值小于
          {
            PwmValue = 0;//脉冲宽度值清0
           }
           CCAP0H = CCAP0L = PwmValue;//脉冲宽度值赋给CCP/PCA/PWM模块0高低八位捕获/比较寄存器
           KeyNumber = 0;//按键键值清0
           break;//跳出
   default:break;//跳出
  }
 }




你可能感兴趣的:(单片机,c语言)